<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 'react';
// 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) => {
setLoading(true);
try {
// Simulando chamada à API
await new Promise(resolve => setTimeout(resolve, 1000));
setUser({ email, id: Math.random() });
} finally {
setLoading(false);
}
};
const logout = () => {
setUser(null);
};
return (
<AuthContext.Provider value={{ user, loading, login, logout }}>
{children}
</AuthContext.Provider>
);
}
// 3. Hook customizado para usar o contexto
export function useAuth() {
const context = useContext(AuthContext);
if (!context) {
throw new Error('useAuth deve ser usado dentro de AuthProvider');
}
return context;
}</code></pre>
<p>Agora use no seu App:</p>
<pre><code class="language-javascript">function App() {
return (
<AuthProvider>
<Dashboard />
</AuthProvider>
);
}
function Dashboard() {
const { user, login, logout, loading } = useAuth();
if (!user) {
return (
<button onClick={() => login('user@example.com', '123')}>
{loading ? 'Autenticando...' : 'Login'}
</button>
);
}
return (
<div>
<p>Bem-vindo, {user.email}</p>
<button onClick={logout}>Logout</button>
</div>
);
}</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 'zustand';
const useAuthStore = create((set) => ({
user: null,
loading: false,
login: async (email, password) => {
set({ loading: true });
try {
await new Promise(resolve => setTimeout(resolve, 1000));
set({ user: { email, id: Math.random() } });
} finally {
set({ loading: false });
}
},
logout: () => {
set({ user: null });
}
}));
// Componente consumidor
function Dashboard() {
const user = useAuthStore((state) => state.user);
const login = useAuthStore((state) => state.login);
const logout = useAuthStore((state) => state.logout);
const loading = useAuthStore((state) => state.loading);
if (!user) {
return (
<button onClick={() => login('user@example.com', '123')}>
{loading ? 'Autenticando...' : 'Login'}
</button>
);
}
return (
<div>
<p>Bem-vindo, {user.email}</p>
<button onClick={logout}>Logout</button>
</div>
);
}</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) => 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) => state.user);
// Ou use a função shallowEqual para múltiplas propriedades
import { shallow } from 'zustand/react/shallow';
const { user, loading } = useAuthStore(
(state) => ({ 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 'zustand';
import { devtools, persist } from 'zustand/middleware';
const useAuthStore = create(
devtools(
persist(
(set) => ({
user: null,
logout: () => set({ user: null }),
}),
{ name: 'auth-store' }
)
)
);</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) => ({
items: [],
addItem: (product) => set((state) => ({
items: [...state.items, product]
})),
removeItem: (id) => set((state) => ({
items: state.items.filter(item => item.id !== id)
})),
total: () => // 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 "melhor" — 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>