JavaScript

Boas Práticas de Gerenciamento de Estado em React: Context API e Zustand para Times Ágeis

8 min de leitura

Boas Práticas de Gerenciamento de Estado em React: Context API e Zustand para Times Ágeis

Context API: Fundamentos e Implementação A Context API é nativa do React e permite compartilhar estado entre componentes sem prop drilling. Ela cria um contexto que armazena dados e os disponibiliza para qualquer componente descendente que o consuma. Para iniciantes, é a solução ideal porque não requer dependências externas. Vamos criar um exemplo prático com um tema de autenticação: Agora use no seu App: Limitações da Context API e Quando Evitar A Context API é poderosa, mas tem limitações importantes. Qualquer mudança no contexto causa re-render de todos os componentes que o consomem, mesmo que usem apenas parte dos dados. Em aplicações com estado complexo e frequentes atualizações, isso impacta performance. Além disso, não há ferramentas nativas para debugging ou time-travel. Para aplicações pequenas ou médias com estado simples, a Context API é perfeita. Mas quando o estado é complexo, com múltiplas ações e atualizações frequentes, considere alternativas como Zustand. A regra prática: se seu contexto mudar mais de 10

<h2>Context API: Fundamentos e Implementação</h2>

<p>A Context API é nativa do React e permite compartilhar estado entre componentes sem prop drilling. Ela cria um contexto que armazena dados e os disponibiliza para qualquer componente descendente que o consuma. Para iniciantes, é a solução ideal porque não requer dependências externas.</p>

<p>Vamos criar um exemplo prático com um tema de autenticação:</p>

<pre><code class="language-javascript">import React, { createContext, useState, useContext } from &#039;react&#039;;

// 1. Criar o contexto

const AuthContext = createContext();

// 2. Criar o provider (gerenciador de estado)

export function AuthProvider({ children }) {

const [user, setUser] = useState(null);

const [loading, setLoading] = useState(false);

const login = async (email, password) =&gt; {

setLoading(true);

try {

// Simulando chamada à API

await new Promise(resolve =&gt; setTimeout(resolve, 1000));

setUser({ email, id: Math.random() });

} finally {

setLoading(false);

}

};

const logout = () =&gt; {

setUser(null);

};

return (

&lt;AuthContext.Provider value={{ user, loading, login, logout }}&gt;

{children}

&lt;/AuthContext.Provider&gt;

);

}

// 3. Hook customizado para usar o contexto

export function useAuth() {

const context = useContext(AuthContext);

if (!context) {

throw new Error(&#039;useAuth deve ser usado dentro de AuthProvider&#039;);

}

return context;

}</code></pre>

<p>Agora use no seu App:</p>

<pre><code class="language-javascript">function App() {

return (

&lt;AuthProvider&gt;

&lt;Dashboard /&gt;

&lt;/AuthProvider&gt;

);

}

function Dashboard() {

const { user, login, logout, loading } = useAuth();

if (!user) {

return (

&lt;button onClick={() =&gt; login(&#039;user@example.com&#039;, &#039;123&#039;)}&gt;

{loading ? &#039;Autenticando...&#039; : &#039;Login&#039;}

&lt;/button&gt;

);

}

return (

&lt;div&gt;

&lt;p&gt;Bem-vindo, {user.email}&lt;/p&gt;

&lt;button onClick={logout}&gt;Logout&lt;/button&gt;

&lt;/div&gt;

);

}</code></pre>

<h2>Limitações da Context API e Quando Evitar</h2>

<p>A Context API é poderosa, mas tem limitações importantes. Qualquer mudança no contexto causa re-render de todos os componentes que o consomem, mesmo que usem apenas parte dos dados. Em aplicações com estado complexo e frequentes atualizações, isso impacta performance. Além disso, não há ferramentas nativas para debugging ou time-travel.</p>

<p>Para aplicações pequenas ou médias com estado simples, a Context API é perfeita. Mas quando o estado é complexo, com múltiplas ações e atualizações frequentes, considere alternativas como Zustand. A regra prática: se seu contexto mudar mais de 10 vezes por segundo ou gerencia mais de 5 propriedades interdependentes, provavelmente você precisa de Zustand.</p>

<h2>Zustand: Estado Simples e Performático</h2>

<p>Zustand é uma biblioteca minimalista (2KB gzipped) que oferece gerenciamento de estado sem o overhead da Context API. Ela usa Hooks nativos do React e permite criar stores de forma simples e direta. Zustand só re-renderiza componentes quando a parte específica do estado que eles usam muda.</p>

<p>Vamos recriar o exemplo de autenticação com Zustand:</p>

<pre><code class="language-javascript">import { create } from &#039;zustand&#039;;

const useAuthStore = create((set) =&gt; ({

user: null,

loading: false,

login: async (email, password) =&gt; {

set({ loading: true });

try {

await new Promise(resolve =&gt; setTimeout(resolve, 1000));

set({ user: { email, id: Math.random() } });

} finally {

set({ loading: false });

}

},

logout: () =&gt; {

set({ user: null });

}

}));

// Componente consumidor

function Dashboard() {

const user = useAuthStore((state) =&gt; state.user);

const login = useAuthStore((state) =&gt; state.login);

const logout = useAuthStore((state) =&gt; state.logout);

const loading = useAuthStore((state) =&gt; state.loading);

if (!user) {

return (

&lt;button onClick={() =&gt; login(&#039;user@example.com&#039;, &#039;123&#039;)}&gt;

{loading ? &#039;Autenticando...&#039; : &#039;Login&#039;}

&lt;/button&gt;

);

}

return (

&lt;div&gt;

&lt;p&gt;Bem-vindo, {user.email}&lt;/p&gt;

&lt;button onClick={logout}&gt;Logout&lt;/button&gt;

&lt;/div&gt;

);

}</code></pre>

<h3>Otimizações Avançadas com Zustand</h3>

<p>Para máxima performance, use seletores granulares. No exemplo acima, cada linha <code>useAuthStore((state) =&gt; state.propriedade)</code> seleciona apenas uma propriedade. Isso garante que o componente só re-renderize quando aquela propriedade específica mudar.</p>

<pre><code class="language-javascript">// Antes (renderiza em qualquer mudança do store)

const auth = useAuthStore();

// Depois (renderiza apenas quando user mudar)

const user = useAuthStore((state) =&gt; state.user);

// Ou use a função shallowEqual para múltiplas propriedades

import { shallow } from &#039;zustand/react/shallow&#039;;

const { user, loading } = useAuthStore(

(state) =&gt; ({ user: state.user, loading: state.loading }),

shallow

);</code></pre>

<p>Zustand também oferece middleware para persistência e devtools:</p>

<pre><code class="language-javascript">import { create } from &#039;zustand&#039;;

import { devtools, persist } from &#039;zustand/middleware&#039;;

const useAuthStore = create(

devtools(

persist(

(set) =&gt; ({

user: null,

logout: () =&gt; set({ user: null }),

}),

{ name: &#039;auth-store&#039; }

)

)

);</code></pre>

<h2>Comparação Prática: Quando Usar Cada Uma</h2>

<div class="table-wrap"><table><thead><tr><th>Aspecto</th><th>Context API</th><th>Zustand</th></tr></thead><tbody><tr><td><strong>Dependência externa</strong></td><td>Não</td><td>Sim (2KB)</td></tr><tr><td><strong>Curva de aprendizado</strong></td><td>Mais suave</td><td>Muito rápida</td></tr><tr><td><strong>Performance em grandes stores</strong></td><td>Pode sofrer</td><td>Excelente</td></tr><tr><td><strong>DevTools nativas</strong></td><td>Não</td><td>Sim, com middleware</td></tr><tr><td><strong>Ideal para</strong></td><td>Estado simples, múltiplos contextos</td><td>Estado complexo e centralizado</td></tr></tbody></table></div>

<p>Use <strong>Context API</strong> para: temas, idiomas, autenticação simples, preferências do usuário que mudam raramente. Use <strong>Zustand</strong> para: carrinho de compras, estados de formulários complexos, cache de dados, qualquer estado que mude frequentemente.</p>

<p>Um exemplo real: um e-commerce com contexto de tema (Context API) e store de carrinho (Zustand):</p>

<pre><code class="language-javascript">// Tema simples com Context API

const ThemeContext = createContext();

// Carrinho complexo com Zustand

const useCartStore = create((set) =&gt; ({

items: [],

addItem: (product) =&gt; set((state) =&gt; ({

items: [...state.items, product]

})),

removeItem: (id) =&gt; set((state) =&gt; ({

items: state.items.filter(item =&gt; item.id !== id)

})),

total: () =&gt; // lógica complexa

}));</code></pre>

<h2>Conclusão</h2>

<p>A <strong>Context API</strong> é sua porta de entrada para gerenciamento de estado em React — simples, sem dependências, perfeita para estado compartilhado que muda ocasionalmente. A <strong>Zustand</strong> é o upgrade natural quando a complexidade crescer: menor overhead, melhor performance, ferramentas robustas.</p>

<p>O segredo é começar simples. Use Context API, aprenda seus limites, e migre para Zustand quando a necessidade aparecer. Ambas coexistem bem em um projeto real: use Context para configurações globais e Zustand para estado de aplicação dinâmico. Não existe &quot;melhor&quot; — existe o certo para cada caso.</p>

<h2>Referências</h2>

<ul>

<li><a href="https://react.dev/reference/react/useContext" target="_blank" rel="noopener noreferrer">React Context API - Documentação Oficial</a></li>

<li><a href="https://github.com/pmndrs/zustand" target="_blank" rel="noopener noreferrer">Zustand - Repositório GitHub</a></li>

<li><a href="https://blog.logrocket.com/react-context-api-vs-state-management-libraries/" target="_blank" rel="noopener noreferrer">State Management com React - LogRocket</a></li>

<li><a href="https://docs.pmnd.rs/zustand/" target="_blank" rel="noopener noreferrer">Zustand Documentação Oficial</a></li>

<li><a href="https://dev.to/thadeu/otimizando-context-api-react-2023-4fh3" target="_blank" rel="noopener noreferrer">Performance em React Context - Dev.to</a></li>

</ul>

Comentários

Mais em JavaScript

Guia Completo de Operadores em JavaScript: Aritméticos, Lógicos, Ternário e Nullish
Guia Completo de Operadores em JavaScript: Aritméticos, Lógicos, Ternário e Nullish

Operadores Aritméticos: Os Pilares das Contas Os operadores aritméticos são f...

Boas Práticas de ESLint e Prettier em JavaScript: Qualidade e Formatação de Código para Times Ágeis
Boas Práticas de ESLint e Prettier em JavaScript: Qualidade e Formatação de Código para Times Ágeis

O que são ESLint e Prettier? ESLint é um analisador estático de código JavaSc...

Callbacks em JavaScript: O Padrão Original de Assincronismo: Do Básico ao Avançado
Callbacks em JavaScript: O Padrão Original de Assincronismo: Do Básico ao Avançado

Callbacks em JavaScript: O Padrão Original de Assincronismo O que é um Callba...