Capítulo 08: Context API (useContext) e Criação de Custom Hooks
Especialização Frontend com React & TypeScript • React 19, Hooks, Estado Global e Next.js
🗺️ Mapa Conceitual do Tópico
flowchart TD
ROOT["App Root"] --> PROVIDER["ThemeProvider.Provider (value)"]
PROVIDER --> COMP_A["Componente Intermediário A"]
COMP_A --> COMP_B["Componente Intermediário B (Zero Props!)"]
COMP_B --> CONSUMER["BotaoTema (useTheme Hook)"]
style PROVIDER fill:#ede7f6,stroke:#7e57c2,stroke-width:2px
style CONSUMER fill:#e8f5e9,stroke:#4caf50,stroke-width:2px
🏛️ 1. O Problema do Prop Drilling e a Context API
Quando um dado precisa ser acessado por múltiplos componentes em diferentes níveis da árvore (como dados de usuário autenticado, tema visual ou preferências de idioma), repassá-lo manualmente via props através de componentes intermediários chama-se Prop Drilling.
A Context API resolve esse problema criando um canal direto de teletransporte de dados entre o Provider (no topo) e os Consumidores (nas folhas).
🎣 2. Criação de Custom Hooks Defensivos
Um Custom Hook é uma função JavaScript cujo nome inicia obrigatoriamente com use e que pode invocar outros Hooks nativos do React.
Encapsular o consumo do contexto em um Custom Hook defensivo garante que erros de consumo fora da árvore do Provider sejam interceptados com mensagens de erro claras em tempo de desenvolvimento.
📊 3. Matriz de Decisão: Context API vs Estado Global (Zustand/Redux)
| Critério | Context API Nativa | Estado Global Externo (Zustand/RTK) |
|---|---|---|
| Instalação | Zero dependências (Nativa do React) | Requer pacote externo |
| Frequência de Atualização | Baixa frequência (Temas, Auth, Idioma) | Alta frequência (Carrinho, Dashboards, Canvas) |
| Performance de Re-render | Todos os consumidores re-renderizam na mudança | Re-renders cirúrgicos via seletores atômicos |
| Complexidade | Simples | Moderada a Alta |
⚠️ 4. Armadilhas Comuns e Anti-Padrões de Produção
- Contexto Monolítico Gigantesco: Colocar toda a aplicação dentro de um único
AppContextcontendo centenas de estados faz com que qualquer alteração de texto re-renderize a aplicação inteira. - Criação de Objetos de Valor sem Memoização: Passar
value={{ theme, toggleTheme }}com objeto literal no Provider recria o objeto a cada render do pai, disparando re-renders em todos os consumidores mesmo que o valor interno não tenha mudado. UseuseMemono valor do Provider.
💡 5. Diretrizes de Engenharia (Meta & React Docs)
- Segregue Dados de Funções de Ação: Considere criar um
CartStateContext(apenas leitura de itens) e umCartDispatchContext(apenas dispatch de ações), evitando que componentes que apenas disparam ações re-renderizem quando o estado mudar. - Lance Erro Descritivo no Custom Hook: Sempre valide
if (!context) throw new Error("useMeuContext deve estar dentro do Provider").
💻 6. Demonstração Arquitetural do Conceito
// UserContext.tsx - Contexto defensivo completo
import React, { createContext, useContext, useState } from "react";
interface UserContextType {
user: string | null;
login: (name: string) => void;
}
const UserContext = createContext<UserContextType | null>(null);
export function useUser(): UserContextType {
const ctx = useContext(UserContext);
if (!ctx) throw new Error("useUser deve ser consumido dentro de UserProvider");
return ctx;
}
📋 7. Cheat-Sheet da Context API
- 🔹
createContext<T | null>(null): Cria o canal tipado. - 🔹
<Context.Provider value={memoizedValue}>: Fornece os dados na árvore. - 🔹
useContext(Context): Consome o dado na folha. - 🔹 Custom Hook wrapper: Blinda o consumo contra uso indevido.
🔍 8. Diagnóstico de Performance & React DevTools Profiler
Identificação de gargalos em Contextos:
- Re-render em Massa: Se todos os consumidores do contexto renderizarem a cada tecla digitada, divida o contexto em fatias menores ou migre o estado frequente para uma store atômica com Zustand.
- Context Display Name: Defina
MeuContexto.displayName = "AuthContext"para facilitar a inspeção na árvore do DevTools.
🧪 9. Casos de Teste e Cenários de Borda Recomendados
- 🔍 Consumo Fora do Provider: Valide se o Custom Hook lança uma exceção explicativa com a mensagem esperada no teste unitário.
- 🔍 Providers Aninhados: Teste o comportamento de sobreposição quando dois Providers do mesmo contexto são aninhados.
- 🔍 Troca Dinâmica de Tema: Valide a persistência da preferência do usuário no
localStorage.