Context API — Padrões e Limitações
Context para dados estáveis, splitting por frequência, e o padrão Provider + hook customizado.
Definição
Context API é nativa do React — sem dependências externas. Ideal para dados que: mudam raramente (tema, idioma, usuário logado), ou precisam ser acessados em muitos níveis de profundidade sem prop drilling. Limitação crítica: qualquer mudança no value re-renderiza TODOS os consumers, mesmo que não usem o valor que mudou.
Problema → Solução
Problema
Context com objeto grande onde qualquer campo muda frequentemente: todos os consumers re-renderizam a cada mudança. Difícil otimizar sem usar libs extras. Acesso direto ao Context espalhado no código em vez de hooks customizados.Solução
Splitting: um Context por frequência de atualização (AuthContext separado de ThemeContext). Memoizar value com useMemo. Sempre expor via hook customizado (useAuth()) em vez de useContext(AuthContext) direto — facilita troca de implementação. Para estado frequente, Zustand.Dica de entrevista
Tip
O padrão correto: Context armazena o valor, hook customizado encapsula o acesso. `export function useTheme() { return useContext(ThemeContext) }`. Isso permite trocar a implementação interna sem mudar todos os consumers.Código
// Padrão: Context + hook customizado
interface AuthContextValue {
user: User | null
login: (credentials: Credentials) => Promise<void>
logout: () => void
}
const AuthContext = createContext<AuthContextValue | null>(null)
export function AuthProvider({ children }: { children: ReactNode }) {
const [user, setUser] = useState<User | null>(null)
const login = useCallback(async (credentials) => {
const user = await authApi.login(credentials)
setUser(user)
}, [])
const logout = useCallback(() => setUser(null), [])
// useMemo evita novo objeto a cada render
const value = useMemo(
() => ({ user, login, logout }),
[user, login, logout]
)
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>
}
// Hook customizado — nunca expor o Context diretamente
export function useAuth() {
const ctx = useContext(AuthContext)
if (!ctx) throw new Error('useAuth deve ser usado dentro de AuthProvider')
return ctx
}
// Context splitting — frequências separadas
<ThemeProvider> {/* muda raramente */}
<AuthProvider> {/* muda ao login/logout */}
<UIProvider> {/* muda por interação */}
<App />
</UIProvider>
</AuthProvider>
</ThemeProvider>Perguntas de entrevista
Q.Como otimizar Context para evitar re-renders?▾
A.Splitting: separar contextos por frequência (AuthContext, ThemeContext, UIContext). Memoizar o value: `const value = useMemo(() => ({ user, logout }), [user])`. Para seletores (só ouvir parte do context), usar use-context-selector lib. Mas se o estado muda frequentemente, Zustand é a solução certa.
Q.Context API pode substituir Redux?▾
A.Para estado simples e raramente atualizado, sim. Para estado complexo com muitas atualizações, não — sem o conceito de seletor, todos os consumers re-renderizam. Context não tem devtools, middleware, ou estrutura para mutations complexas. Use Context para DI (dependency injection) de valores estáveis, Redux/Zustand para estado dinâmico.
Q.O que é o padrão Compound + Context?▾
A.Compound Components que compartilham estado via Context: o componente pai cria um Context privado, filhos consomem. Ex: <Accordion> cria um Context com {openIndex, setOpenIndex}. <Accordion.Item> consome via useContext interno. Usuário não precisa gerenciar estado — a API é declarativa.
Termos relacionados
69/122← →