paint-brush
Como simplificar o gerenciamento de estado com a API de contexto React.js – um tutorialpor@codebucks
669 leituras
669 leituras

Como simplificar o gerenciamento de estado com a API de contexto React.js – um tutorial

por CodeBucks11m2024/08/02
Read on Terminal Reader

Muito longo; Para ler

Este blog oferece um guia completo sobre como gerenciar o estado no React usando a API Context. Ele explica como evitar a perfuração de suporte, melhorar o desempenho e implementar a API de contexto de maneira eficaz. Com exemplos práticos e dicas de otimização, é perfeito para desenvolvedores que buscam agilizar o gerenciamento de estado em suas aplicações React.
featured image - Como simplificar o gerenciamento de estado com a API de contexto React.js – um tutorial
CodeBucks HackerNoon profile picture
0-item

Olá👋🏻,


Este artigo foi criado especificamente para iniciantes que desejam aprender métodos mais eficazes para gerenciar o estado entre vários componentes. Ele também visa resolver o problema comum de perfuração de suporte, que pode tornar seu código mais difícil de manter e entender. Vamos começar explicando que tipo de problema a API de contexto resolve.


Se preferir o formato de vídeo, aqui está o tutorial que você pode assistir no meu canal no YouTube.👇🏻


O que é perfuração auxiliar?

Você sabe como às vezes você precisa passar dados de um componente pai para um componente filho e acaba passando adereços por meio de vários componentes intermediários? Isso é chamado de perfuração de hélice e pode ficar confuso rapidamente. Vejamos um exemplo para esclarecer isso.


Perfuração de adereços em React.js

Conforme mostrado no diagrama, imagine que você buscou alguns dados no componente App , que fica na raiz do seu aplicativo. Agora, se um componente profundamente aninhado, digamos o componente Grandchild , precisar acessar esses dados, você normalmente os transmitiria através dos componentes Parent e Child como adereços antes de chegar Grandchild . Isso pode ficar feio à medida que seu aplicativo cresce.


Aqui está outra representação visual:


Exemplo de perfuração de adereços Reactjs

No exemplo acima, o componente Profile precisa de dados do usuário, mas esses dados precisam passar primeiro pelos componentes App e Navigation , mesmo que esses componentes intermediários não usem os dados em si. Então, como podemos limpar isso? É aí que a API Context se torna útil.


Perfuração de adereços:

  • Aumenta a nova renderização de componentes
  • Aumenta o código padrão
  • Cria dependência de componente
  • Diminui o desempenho

API de contexto de reação

A API de contexto em React.js permite passar dados entre componentes sem a necessidade de passá-los como acessórios em cada nível da árvore de componentes. Funciona como um sistema de gerenciamento de estado global onde você define seu estado em um objeto de contexto e pode acessá-lo facilmente em qualquer lugar na árvore de componentes. Vamos entender isso com um exemplo.


API de contexto React.js

Como você pode ver no diagrama, temos um objeto de contexto que armazena dados que serão acessados por múltiplos componentes. Esses dados são obtidos de APIs ou serviços de terceiros. Antes de acessar esses dados de contexto em qualquer componente, precisamos agrupar todos os componentes que requerem esses dados em um componente provedor de contexto.


Se precisarmos apenas acessar dados nos componentes de navegação e perfil, não precisaremos finalizar o componente app. Depois de agrupar os componentes relevantes com ContextProvider , você poderá acessar diretamente os dados de contexto em qualquer componente que os consuma. Não se preocupe se ainda não entendeu; vamos mergulhar no código e vê-lo em ação.


Como usar a API de contexto?

Primeiro, vamos criar um aplicativo React usando Vite.js. Basta copiar os seguintes comandos para configurar o projeto.


 npm create vite@latest


  • Adicione o nome do seu projeto
  • Selecione Reagir
  • Selecione texto datilografado nas opções
 cd project_name // to change to project directory npm install npm run dev


Então você pode abrir seu servidor de desenvolvimento http://localhost:5173 em seu navegador.


Primeiro, vamos criar as pastas necessárias. Aqui está a estrutura de pastas do nosso projeto.

 src | components | context


Na pasta de componentes vamos criar o arquivo Profile.jsx e adicionar o seguinte código.

 import React from 'react' const Profile = () => { return ( <div>Profile</div> ) } export default Profile


Crie mais um componente chamado Navbar.jsx na pasta de componentes.

 import Profile from './Profile' const Navbar = () => { return ( <nav style={{ display: "flex", justifyContent: "space-between", alignItems: "center", width: "90%", height: "10vh", backgroundColor: theme === "light" ? "#fff" : "#1b1b1b", color: theme === "light" ? "#1b1b1b" : "#fff", border: "1px solid #fff", borderRadius: "5px", padding: "0 20px", marginTop: "40px", }}> <h1>LOGO</h1> <Profile /> </nav> ) } export default Navbar


Vamos importar este componente <Navbar /> no arquivo App.jsx .

 import Navbar from "./components/Navbar"; function App() { return ( <main style={{ display: "flex", flexDirection: "column", justifyContent: "start", alignItems: "center", height: "100vh", width: "100vw", }} > <Navbar /> </main> ); } export default App;


Então, basicamente, o componente <Profile /> é filho de <Navbar /> e <Navbar /> é filho do componente <App /> .

Adicionando API de Contexto

Vamos criar o arquivo UserContext.jsx na pasta context . Adicione o seguinte código ao arquivo.


 import { createContext, useEffect, useState } from "react"; export const UserContext = createContext(); export const UserProvider = ({ children }) => { const [user, setUser] = useState(null); const fetchUserData = async (id) => { const response = await fetch( `https://jsonplaceholder.typicode.com/users/${id}` ).then((response) => response.json()); console.log(response); setUser(response); }; useEffect(() => { fetchUserData(1); }, []); return ( <UserContext.Provider value={{ user, fetchUserData }} > {children} </UserContext.Provider> ); };


  • Primeiro, criamos um objeto UserContext vazio usando createContext . Certificamo-nos de importá-lo de react . Podemos adicionar valores padrão dentro do objeto de contexto, mas o mantemos nulo por enquanto.


  • A seguir, criamos UserProvider , que retorna um provedor usando UserContext , como UserContext.Provider . Ele envolve os componentes filhos e, no valor, podemos passar qualquer coisa que quisermos usar nos componentes filhos.


  • No momento, estamos usando a API jsonplaceholder para buscar os dados do usuário. O jsonplaceholder fornece endpoints de API falsos para fins de teste. A função fetchUserData aceita id e usa esse ID para buscar os dados do usuário. Em seguida, armazenamos a resposta no estado user .


  • Estamos chamando a função fetchUserData no useEffect , portanto, no carregamento da página, ele chama a função e injeta os dados no estado user .


Agora, vamos usar esse contexto no componente <App /> . Envolva o componente <NavBar /> usando <UserProvider /> ; o mesmo que o seguinte código:

 <UserProvider> <Navbar /> </UserProvider>


Vamos usar o estado user no componente <Profile /> . Para isso, usaremos o gancho useContext . Isso pega UserContext e fornece os valores que passamos no UserProvider como estado user e função fetchUserData . Lembre-se, não precisamos agrupar o componente <Profile /> pois ele já está no componente <Navbar /> que já está agrupado com o provedor.


Abra o Profile.jsx e adicione o código a seguir.

 const { user } = useContext(UserContext); if (user) { return ( <span style={{ fontWeight: "bold", }} > {user.name} </span> ); } else { return <span>Login</span>; }


Aqui, estamos usando o estado user do UserContext . Exibiremos o nome de usuário se houver user , caso contrário, exibiremos apenas uma mensagem de login. Agora, se você vir a saída, deverá haver um nome de usuário no componente da barra de navegação. É assim que podemos usar diretamente qualquer estado que esteja no contexto de qualquer componente. O componente que usa esse estado deve ser agrupado em <Provider /> .


Você também pode usar vários contextos. Você só precisa agrupar os componentes do provedor em outro componente do provedor, conforme mostrado no exemplo a seguir.

 <ThemeProvider> <UserProvider> <Navbar /> </UserProvider> </ThemeProvider>


No exemplo acima, estamos usando <ThemeProvider /> que gerencia o estado do tema.


Você pode assistir ao vídeo do YouTube acima para ver o exemplo completo do uso de vários provedores de contexto.

Otimizando a nova renderização na API React Context

Há um problema que ocorre quando você usa a API Context em vários componentes. Sempre que o estado ou valor muda na API de contexto, ela renderiza novamente todos os componentes inscritos naquele contexto específico, mesmo que nem todos os componentes estejam usando o estado alterado. Para entender esse problema de nova renderização, vamos criar um componente <Counter /> que usa contexto para armazenar e exibir valores de contagem.


Confira o exemplo a seguir. Você pode criar um arquivo Counter.jsx na pasta de componentes e colar o código a seguir.


 import { createContext, memo, useContext, useState } from "react"; const CountContext = createContext(); const CountProvider = ({ children }) => { const [count, setCount] = useState(0); return ( <CountContext.Provider value={{ count, setCount }}> {children} </CountContext.Provider> ); }; function CountTitle() { console.log("This is Count Title component"); return <h1>Counter Title</h1>; } function CountDisplay() { console.log("This is CountDisplay component"); const { count } = useContext(CountContext); return <div>Count: {count}</div>; } function CounterButton() { console.log("This is CounterButton component"); const { count, setCount } = useContext(CountContext); return ( <> <CountTitle /> <CountDisplay /> <button onClick={() => setCount(count + 1)}>Increase</button> </> ); } export default function Counter() { return ( <CountProvider> <CounterButton /> </CountProvider> ); }


No código acima:

  • Primeiro, criamos um objeto CountContext usando createContext.


  • No CountProvider, temos um estado para armazenar valores de contagem. Estamos enviando count e o método setCount para os componentes filhos por meio da proposta de valor.


  • Criamos componentes separadamente para ver quantas vezes os componentes individuais são renderizados novamente.

    • <CountTitle /> : Este componente exibe apenas o título e nem mesmo usa nenhum valor do contexto.

    • <CountDisplay /> : Este componente exibe valores de contagem e usa o estado count do contexto.

    • <CounterButton /> : Este componente renderiza o componente acima e um botão que aumenta os valores de contagem usando setCount .


  • Ao final, estamos agrupando o componente <CounterButton /> dentro do componente CountProvider para que os demais componentes possam acessar os valores de contagem.


Agora, se você executar o código e clicar no botão Increase , verá nos logs que cada componente é renderizado novamente cada vez que o estado muda. O <CountTitle /> nem mesmo está usando valores de contagem, mas está sendo renderizado novamente. Isso está acontecendo porque o componente pai de <CountTitle /> que é <CounterButton /> está usando e atualizando o valor de count e é por isso que está sendo renderizado novamente.


Como podemos otimizar esse comportamento? A resposta é memo . O memo React permite pular a nova renderização de um componente quando seus adereços permanecem inalterados. Após o componente <CountTitle /> , vamos adicionar a seguinte linha.


 const MemoizedCountTitle = React.memo(CountTitle)


Agora, no componente <CounterButton /> , onde estamos renderizando o componente <CountTitle /> , substitua <CountTitle /> por <MemoizedCountTitle /> como no código a seguir:


 <> <MemoizedCountTitle /> <CountDisplay /> <button onClick={() => setCount(count + 1)}>Increase</button> </>


Agora, se você aumentar a contagem e verificar os logs, poderá ver que ele não está mais renderizando o componente <CountTitle /> .

API Redux vs Contexto

O Redux é uma biblioteca de gerenciamento de estado para gerenciamento de estado complexo com transições de estado mais previsíveis. Enquanto a API Context foi projetada para gerenciamento simples de estado e passagem de dados pela árvore de componentes sem perfuração de suporte. Então, quando escolher qual?


  • Use a API React Context para gerenciamento de estado simples e localizado onde o estado não muda com frequência.


  • Use o Redux para necessidades complexas de gerenciamento de estado, especialmente em aplicações maiores, onde os benefícios de seu gerenciamento de estado estruturado superam a configuração extra.


Há também mais uma biblioteca que também é uma opção popular para gestão estadual. O recuo da reação .


  • O React Recoil é uma biblioteca de gerenciamento de estado para React que visa fornecer a simplicidade da API Context com o poder e desempenho do Redux.


Se você estiver interessado em aprender mais sobre o React Recoil , deixe-me saber nos comentários e criarei tutoriais detalhados sobre este tópico com base no seu feedback.

Conclusão

A API de contexto React.js oferece uma maneira poderosa e eficiente de gerenciar estados em vários componentes, abordando efetivamente o problema de perfuração de suporte. Ao usar a API Context, você pode simplificar seu código, reduzir novas renderizações desnecessárias e melhorar o desempenho geral do aplicativo.


Embora a API Context seja ideal para gerenciamento simples de estado, aplicativos mais complexos podem se beneficiar do uso Redux ou de outras bibliotecas de gerenciamento de estado, como React Recoil . Compreender quando e como usar essas ferramentas permitirá que você crie aplicativos React mais sustentáveis e escaláveis.


Obrigado por ler este artigo, espero que você tenha achado útil. Se você estiver interessado em aprender e construir projetos usando React, Redux e Next.js, pode visitar meu canal no YouTube aqui: CodeBucks


Aqui estão meus outros artigos que você pode gostar de ler:

Visite meu blog pessoal: DevDreaming