Hook useContext
Leia e assine o contexto de qualquer componente sem prop drilling.
Busque em todas as páginas da documentação
Leia e assine o contexto de qualquer componente sem prop drilling.
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥
Cartão de receita de referência rápida - pronto para copiar e colar.
// 1. Crie o contexto
const ThemeContext = createContext<Theme>("light");
// 2. Forneça-o
<ThemeContext.Provider value={theme}>
<App />
</ThemeContext.Provider>
// 3. Consuma-o
const theme = useContext(ThemeContext);Quando usar: Você precisa compartilhar valores (tema, autenticação, local) entre muitos componentes sem passar props em cada nível.
"use client";
import { createContext, useContext, useState, type ReactNode } from "react";
type Theme = "light" | "dark";
const ThemeContext = createContext<Theme>("light");
const ThemeToggleContext = createContext<() => void>(() => {});
export function ThemeProvider({ children }: { children: ReactNode }) {
const [theme, setTheme] = useState<Theme>("light");
const toggle = () => setTheme((t) => (t === "light" ? "dark" : "light"));
return (
<ThemeContext.Provider value={theme}>
<ThemeToggleContext.Provider value={toggle}>
{children}
</ThemeToggleContext.Provider>
</ThemeContext.Provider>
);
}
export function ThemeDisplay() {
const theme = useContext(ThemeContext);
const toggle = useContext(ThemeToggleContext);
return (
<div className={theme === "dark" ? "bg-gray-900 text-white p-4" : "bg-white text-black p-4"}>
<p>Tema atual: {theme}</p>
<button onClick={toggle} className="mt-2 px-3 py-1 border rounded">
Alternar Tema
</button>
</div>
);
}O que isto demonstra:
createContext e ProvideruseContext em um componente profundamente aninhadouseContext encontra o Provider mais próximo acima do componente que o chama na árvore.value do provedor muda, cada componente que consome esse contexto é re-renderizado.createContext é usado.Object.is) para detectar mudanças - uma nova referência de objeto dispara re-renderizações mesmo que o conteúdo seja idêntico.| Parâmetro | Tipo | Descrição |
|---|---|---|
context | Context<T> | O objeto de contexto criado por createContext |
| Retorno | Tipo | Descrição |
|---|---|---|
value | T | O valor atual do contexto do provedor mais próximo |
Contexto com um hook customizado (padrão recomendado):
const AuthContext = createContext<AuthState | null>(null);
export function useAuth() {
const ctx = useContext(AuthContext);
if (!ctx) throw new Error("useAuth deve ser usado dentro de um AuthProvider");
return ctx;
}Múltiplos contextos compostos:
export function AppProviders({ children }: { children: ReactNode }) {
return (
<AuthProvider>
<ThemeProvider>
<LocaleProvider>
{children}
</LocaleProvider>
</ThemeProvider>
</AuthProvider>
);
}Contexto com reducer para estado complexo:
const DispatchContext = createContext<Dispatch<Action>>(() => {});
const StateContext = createContext<AppState>(initialState);// Sempre tipifique seu contexto - evite `any`
const UserContext = createContext<User | null>(null);
// Use um hook customizado para refinar o tipo
export function useUser(): User {
const user = useContext(UserContext);
if (!user) throw new Error("useUser requer um UserProvider");
return user; // refinado para User, nunca null
}Avalanche de re-renderizações - Passar uma nova literal de objeto como value a cada renderização faz com que todos os consumidores re-renderizem. Correção: Memoize o valor com useMemo ou divida em contextos separados.
Provedor ausente - Esquecer o Provider retorna silenciosamente o valor padrão, que pode ser undefined. Correção: Use um hook customizado que lance um erro se o contexto for null.
Uso excessivo de contexto para atualizações de alta frequência - O contexto não é otimizado para valores que mudam a cada pressionamento de tecla ou quadro de animação. Correção: Use useSyncExternalStore, Zustand ou Jotai para estado compartilhado de alta frequência.
Confusão de valor padrão - O padrão em createContext(defaultValue) é usado apenas quando não há provedor, não como estado inicial para o provedor. Correção: Sempre envolva os componentes consumidores no provedor apropriado.
| Alternativa | Use Quando | Não Use Quando |
|---|---|---|
| Prop drilling | Apenas 1–2 níveis de profundidade e poucos consumidores | Muitos níveis ou muitos consumidores |
| Zustand / Jotai | Atualizações de alta frequência ou estado compartilhado complexo | Valores simples e infrequentes como tema ou local |
| Composição de componentes | Filhos podem ser passados como props para evitar que componentes intermediários precisem dos dados | Dados são necessários em muitos níveis arbitrários |
use(Context) (React 19) | Você quer ler o contexto condicionalmente ou em loops | Você precisa suportar React 18 ou anterior |
Por que não usar sempre Zustand? O Contexto é integrado, não requer dependências e é a ferramenta certa para valores de escopo de árvore e baixa frequência, como tema, autenticação ou local.
De uma aplicação SaaS de produção Next.js 15 / React 19 (SystemsArchitect.io).
// Exemplo de produção: ToastProvider com createContext e hook de guarda
// Arquivo: src/components/toast-provider.tsx
'use client';
import { createContext, useContext, useState, useCallback, type ReactNode } from 'react';
interface Toast {
id: string;
message: string;
type: 'success' | 'error' | 'info';
}
interface ToastContextValue {
toasts: Toast[];
showToast: (message: string, type?: Toast['type']) => void;
dismissToast: (id: string) => void;
}
const ToastContext = createContext<ToastContextValue | null>(null);
export function ToastProvider({ children }: { children: ReactNode }) {
const [toasts, setToasts] = useState<Toast[]>([]);
const showToast = useCallback((message: string, type: Toast['type'] = 'info') => {
const id = crypto.randomUUID();
setToasts((prev) => [...prev, { id, message, type }]);
setTimeout(() => {
setToasts((prev) => prev.filter((t) => t.id !== id));
}, 5000);
}, []);
const dismissToast = useCallback((id: string) => {
setToasts((prev) => prev.filter((t) => t.id !== id));
}, []);
return (
<ToastContext.Provider value={{ toasts, showToast, dismissToast }}>
{children}
<div className="fixed bottom-4 right-4 space-y-2 z-50">
{toasts.map((toast) => (
<div key={toast.id} className="rounded bg-gray-900 text-white px-4 py-2 shadow">
{toast.message}
<button onClick={() => dismissToast(toast.id)} className="ml-2">x</button>
</div>
))}
</div>
</ToastContext.Provider>
);
}
// Hook de guarda: lança erro se usado fora do provedor
export function useToast(): ToastContextValue {
const ctx = useContext(ToastContext);
if (!ctx) {
throw new Error('useToast deve ser usado dentro de um ToastProvider');
}
return ctx;
}O que isto demonstra em produção:
createContext<ToastContextValue | null>(null) usa null como padrão para que o hook de guarda possa detectar quando é usado fora de um provedor. Usar um valor padrão real falharia silenciosamente em vez de lançar um erro útil.useCallback em showToast e dismissToast mantém essas referências de função estáveis entre as renderizações. Sem isso, qualquer componente que consumisse useToast() seria re-renderizado a cada mudança de estado do toast, pois o objeto de valor do contexto conteria novas referências de função.setToasts((prev) => ...)) são usadas em vez de ler toasts diretamente. Isso evita adicionar toasts ao array de dependências do useCallback, o que quebraria a referência estável.setTimeout para descarte automático captura o id em seu closure e usa um atualizador funcional para filtrar. Isso evita bugs de closure obsoleto onde o array toasts mudou quando o timeout é acionado.useToast() refina o tipo de ToastContextValue | null para ToastContextValue, para que os consumidores nunca precisem lidar com null. O throw garante uma mensagem de erro clara durante o desenvolvimento se o provedor estiver ausente.createContext(defaultValue).undefined ou null, seu componente pode falhar silenciosamente.null para capturar isso durante o desenvolvimento.const MyContext = createContext<MyType | null>(null);
export function useMyContext(): MyType {
const ctx = useContext(MyContext);
if (!ctx) throw new Error("useMyContext deve ser usado dentro de um Provider");
return ctx; // refinado para MyType, nunca null
}Object.is para detectar mudanças. Passar uma nova literal de objeto { theme, toggle } como valor do provedor cria uma nova referência a cada renderização.useMemo:const value = useMemo(() => ({ theme, toggle }), [theme, toggle]);
return <ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>;useSyncExternalStore, Zustand ou Jotai em vez disso.createContext(default) é usado apenas quando não há um Provider acima do consumidor.value do Provider é o valor real em tempo de execução passado para os consumidores.function AppProviders({ children }: { children: ReactNode }) {
return (
<AuthProvider>
<ThemeProvider>
<LocaleProvider>
{children}
</LocaleProvider>
</ThemeProvider>
</AuthProvider>
);
}composeProviders que reduz um array de provedores.use(Context) é novo no React 19 e pode ser chamado dentro de condições e loops, diferente de useContext.useContext é a abordagem padrão se você precisar de compatibilidade com React 18.useCallback mantém suas referências estáveis entre as renderizações.// Usa padrão de valor null + hook de guarda
const UserContext = createContext<User | null>(null);
// O hook de guarda refina o tipo
export function useUser(): User {
const user = useContext(UserContext);
if (!user) throw new Error("useUser requer UserProvider");
return user;
}use() do React 19 pode ler contexto condicionalmenteuseContext em um hook customizado para segurança de tipoRevisado por Chris St. John·Última atualização: 16 de jul. de 2026
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥