Skip to content

Adeus useState & useEffect: Revolucionando o Desenvolvimento com React! #4

@gabrielviol

Description

@gabrielviol

Se você está construindo um SaaS, uma ferramenta de IA ou qualquer outra aplicação web e não tem tempo para configurar códigos de base (por exemplo, autenticação, registros DNS, webhooks de pagamento, componentes, animações, etc.), então você precisa do ShipFast. O ShipFast economiza 18+ horas de dor de cabeça de desenvolvimento, é confiável por mais de 300 desenvolvedores e possui uma documentação excelente.

Hoje, quero mostrar a você uma alternativa para os hooks useState e useEffect no React. (Reduz muitos códigos de base)

Muitos desenvolvedores continuam usando os hooks useState e useEffect para atualizar estados, mas eu não sou fã desse método. O problema é que ele faz com que o componente seja montado, remontado e desmontado simultaneamente, levando a comportamentos inesperados. Como resultado, ao registrar algo no console, você pode ver o resultado repetido três vezes.

Apresentando o Hook useLoaderData:

O hook useLoaderData é um hook personalizado no React que ajuda você a carregar dados em seu componente. Ele simplifica o processo de buscar dados de uma API ou realizar qualquer operação assíncrona.

Quando você usa o hook useLoaderData, você fornece a ele uma função que retorna uma Promise. Esta Promise representa uma operação assíncrona que buscará os dados que você precisa. Uma vez que a Promise é resolvida, os dados ficam disponíveis para o seu componente.

O hook useLoaderData cuida do estado de carregamento para você, então você não precisa acompanhar manualmente se os dados ainda estão carregando ou se terminaram de carregar. Ele oferece uma maneira conveniente de acessar os dados e também lida com quaisquer erros potenciais que possam ocorrer durante o processo de carregamento dos dados.

Por que usar o useLoaderHook?

O useLoaderHook do react-router alcança a mesma funcionalidade com o mínimo de esforço. Estes são alguns exemplos do porquê você deve usá-lo:

  • Gestão do estado de carregamento: Loaders gerenciam o estado de carregamento para você, fornecendo uma indicação clara de quando os dados estão sendo buscados. Isso ajuda você a gerenciar spinners de carregamento, indicadores de progresso ou qualquer outro elemento de interface do usuário relacionado ao carregamento de dados.

  • Manipulação de erros: Loaders geralmente incluem mecanismos de tratamento de erros, permitindo que você lide e exiba erros que ocorrem durante o processo de carregamento de dados. Eles fornecem uma maneira padronizada de lidar com erros, facilitando a implementação de tratamento de erros consistente em toda a sua aplicação.

  • Separação de preocupações: Loaders permitem que você separe a lógica de carregamento de dados de outros aspectos do seu componente. Isso promove uma melhor organização e manutenibilidade do código, pois você pode se concentrar em responsabilidades específicas sem misturá-las.

E muito mais.

Vamos ver como isso funciona.

É assumido que você tem um bom conhecimento de como o react-router 6 funciona. Se não, sinta-se à vontade para verificar a [documentação aqui](link para a documentação).

Primeiro, precisamos configurar o sistema de roteamento em nossa aplicação para trabalhar com a API do Loader. Até agora, temos usado a configuração BrowserRouter para lidar com as várias rotas de nossa aplicação. Vamos gastar um pouco de tempo falando sobre isso.

import { BrowserRouter, Routes, Route, Outlet } from "react-router-dom";
import HomeComponent from "./home";
import AboutComponent from "./about";

function App() {
    return (
        <BrowserRouter>
            <Routes>
                <Route path="/" element={<Outlet />}>
                    <Route index element={<HomeComponent />} />
                    <Route path="about" element={<AboutComponent />} />
                </Route>
            </Routes>
        </BrowserRouter>
    );
}

export default App;

Configuração do Sistema de Roteamento com React Router

Neste trecho, configuramos um sistema de roteamento tradicional usando as importações do react-router. Vamos analisar o que está acontecendo por um momento.

Bem. O BrowserRouter do react-router cria uma matriz de objetos a partir dos filhos do Routes. O trecho abaixo fornece uma clara ilustração de como isso está funcionando.

BrowserRouter([
{
    path: '/',
    element: <HomeComponent />,
    children: []
},
{
    path: '/about',
    element: <AboutComponent />,
    children: []
}
])

Se fossem uma rota aninhada, ela anexaria a rota dos filhos à chave children na rota pai.
Sim, é assim que ela continua sendo recursiva.

No entanto, este método não pode ser usado para usar o hook loaderData. Temos que fazer um pouco de refatoração. Não entre em pânico, é um pouco parecido com isso. Eu recomendo que você confira a documentação do react-router para obter mais informações.

import { 
createBrowserRouter,
createRoutesFromElements,
RouterProvider,
Route, 
Outlet
 } from "react-router-dom"

import HomeComponent from "./home"
import AboutComponent from "./about"

function App() {
    const browserRoutes = createBrowserRouter(createRoutesFromElements(
       <Route path='/' element={<Outlet />}>
                <Route index element={<HomeComponent /> } />
                <Route path='about' element={<AboutComponent /> } />
        </Route>
    ))

     return (
        <RouterProvider router={browserRoutes} />
    );
}

Eu importei createBrowserRouter, createRoutesFromElement e RouterProvider. Em seguida, inicializei uma variável chamada browserRoutes para servir como o objeto que deveria ser renderizado. Perceba que eu chamei a função createRoutesFromElements dentro da função createBrowserRouter. Isso aconteceu porque eu queria analisar ou converter as rotas para um objeto, e a função createRoutesFromElements, como o nome sugere, pode me ajudar nisso. Por fim, o RouterProvider foi retornado com o valor do novo browserRouter. Vamos dar uma olhada em como seria sem usar a função createRoutesFromElements.

createBrowserRouter([
{
    path: '/',
    element: <HomeComponent />,
    children: []
},
{
    path: '/about',
    element: <AboutComponent/>,
    children: []
}])

Eu não sou muito fã disso, pois suas rotas podem se tornar aninhadas e, em algum momento, isso se torna confuso. Você deve manter as coisas muito simples.

Explorando as Funções do Carregador:

Agora que temos um pouco de compreensão sobre como configurar nossa aplicação para usar a API do Carregador, vamos ver como podemos usá-la.

Suponha que você pretenda buscar dados de um endpoint para serem exibidos no componente Home. O que a maioria dos desenvolvedores faria é: inicializar um estado e atualizar o estado no gancho useEffect. O trecho de código abaixo fornece uma clara ilustração do que estou falando.

import { useState } from 'react'

const HomeComponent = () => {
    const [data, setData] = useState([]);
    
    useEffect(async () => {
        const request = await fetch('http://localhost:3004/file');
         if(!request.ok) throw new Error('Falha ao buscar dados')
        const item= await request.json()
        setData(item)  
    }, [])

    return (
        <section>
            { data.length > 0 ? data.map((foundData) => (
                    <div key={foundData.id}>
                        <strong>{foundData.name}</strong>
                     </div>
                 )) : <p>Dados indisponíveis no momento</p>}
        </section>
    )
}
export default HomeComponent

Wow! 😲..

Agora, veja como acabamos de simplificar o HomeComponent :)
Perceba que nos livramos da cláusula de proteção que verifica se os dados são nulos.
Isso acontece porque o react-router carrega os dados assim que a url/caminho está ativo. Portanto, ele faz as solicitações necessárias mesmo antes de o componente ser montado. Sim!

Estamos apenas prevendo o caminho feliz. E se passarmos um endpoint que não existe? Se for o caso, não entre em pânico, pois o react-router também nos permite passar componentes para outra propriedade chamada errorElement.
Isso é específico para erros, assim como usamos ErrorBoundaries. Vejamos como isso funciona no trecho de código abaixo:

import { 
createBrowserRouter,
createRoutesFromElements,
RouterProvider,
Route, 
Outlet
 } from "react-router-dom"
import HomeComponent from "./home"
import AboutComponent from "./about"
import { LoaderFunction as HomeLoader} from "./loader"

function App() {
    const browserRoutes = createBrowserRouter(createRoutesFromElements(
       <Route path='/' element={<Outlet />}>
                <Route index element={<HomeComponent /> }
                    loader={HomeLoader} errorElement={<h1>Ocorreu um erro</h1>}/>
                <Route path='about' element={<AboutComponent /> } />
        </Route>
    ))

     return (
        <RouterProvider router={browserRoutes} />
    );
}

Eu acabei de usar uma tag de cabeçalho para mostrar o erro. É aconselhável que você use um componente para que você também possa ter acesso ao Hook useRouteError. Vou mostrar como usar o Hook useRouteError em um dos meus próximos posts no blog. Se você está interessado em aprender sobre isso, por favor, use este link.

Como ele busca os dados antes de montar o componente, o estado de carregamento se torna irrelevante, já que ele pode obter os dados ou retornar a mensagem de erro que você passa como valor para a propriedade errorElement.

Isso é tudo o que você precisa saber sobre como fazer requisições usando a API da Camada de Dados.


Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions