//
Busque em todas as páginas da documentação
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥
Crie contextos React totalmente tipados com createContext, providers tipados e hooks useContext type-safe. Lide com o problema do valor padrão de forma limpa.
// 1. Defina o tipo do contexto
type Theme = "light" | "dark";
type ThemeContextType = {
theme: Theme;
toggleTheme: () => void;
};
// 2. Crie o contexto com um valor padrão sensato ou null
const ThemeContext = createContext<ThemeContextType | null>(null);
// 3. Crie um hook tipado com uma guarda em tempo de execução
function useTheme(): ThemeContextType {
const context = useContext(ThemeContext);
if (!context) {
throw new Error("useTheme deve ser usado dentro de um ThemeProvider");
}
return context;
}
// 4. Crie o componente provider
function ThemeProvider({ children }: { children: React.ReactNode }) {
const [theme, setTheme] = useState<Theme>("light");
const toggleTheme = () => {
setTheme((prev) => (prev === "light" ? "dark" : "light"));
};
return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>
{children}
</ThemeContext.Provider>
);
}
// 5. Consuma em um componente
function Header() {
const { theme, toggleTheme } = useTheme();
return (
<header className={theme}>
<button onClick={toggleTheme}>Atual: {theme}</button>
</header>
);
}createContext<T>(defaultValue) cria um objeto de contexto. O genérico T define a forma do valor que os providers devem fornecer e os consumidores receberão.null como padrão + hook customizado evita dois problemas: (1) inventar um valor padrão falso que poderia mascarar bugs e (2) forçar os consumidores a verificar por undefined em todos os lugares.useTheme() estreita o tipo de ThemeContextType | null para ThemeContextType lançando um erro se o contexto estiver faltando. Isso dá aos consumidores um tipo limpo e não anulável.value do provider muda. Como { theme, toggleTheme } é um novo objeto a cada renderização, envolva-o com useMemo se você tiver muitos consumidores.Contexto com useMemo para valor estável:
function ThemeProvider({ children }: { children: React.ReactNode }) {
const [theme, setTheme] = useState<Theme>("light");
const value = useMemo<ThemeContextType>(
() => ({
theme,
toggleTheme: () => setTheme((prev) => (prev === "light" ? "dark" : "light")),
}),
[theme]
);
return <ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>;
}Múltiplos contextos para preocupações separadas:
type AuthContextType = {
user: User | null;
login: (credentials: Credentials) => Promise<void>;
logout: () => void;
};
const AuthContext = createContext<AuthContextType | null>(null);
function useAuth(): AuthContextType {
const context = useContext(AuthContext);
if (!context) throw new Error("useAuth deve ser usado dentro de AuthProvider");
return context;
}Contexto com useReducer:
type AppState = { count: number; user: User | null };
type AppAction = { type: "increment" } | { type: "setUser"; payload: User };
type AppContextType = {
state: AppState;
dispatch: React.Dispatch<AppAction>;
};
const AppContext = createContext<AppContextType | null>(null);React.Dispatch<React.SetStateAction<T>> é o tipo de um setter do useState. Use-o em tipos de contexto ao expor um setter diretamente.React.Dispatch<Action> é o tipo de uma função de dispatch do useReducer.as para fazer cast do valor padrão: createContext({} as ThemeContextType) compila, mas fornece um objeto inválido em tempo de execução se o provider estiver ausente.createContext({} as T) silencia o TypeScript, mas leva a falhas em tempo de execução quando o provider está ausente. O padrão null + guarda é mais seguro.value a cada renderização faz com que todos os consumidores re-renderizem. Use useMemo para o objeto de valor.useTheme, useAuth) é crítico para uma boa DX. Sem ele, os consumidores precisam importar tanto o contexto quanto useContext, e lidar com null eles mesmos.| Abordagem | Prós | Contras |
|---|---|---|
Padrão null + hook de guarda | Type-safe, erro claro em caso de mau uso | Requer um hook customizado por contexto |
Asserção não-nula ({} as T) | Nenhuma verificação de null necessária | Falha em tempo de execução se o provider estiver ausente |
| Valor padrão real | Funciona sem provider | Precisa inventar um padrão significativo |
| Zustand ou Jotai | API mais simples, assinaturas granulares | Dependência externa |
| Estado em nível de módulo | Sem aninhamento de provider | Não reativo, não seguro para SSR |
createContext({} as T) fornece um objeto inválido que causa silenciosamente falhas em tempo de execução se o provider estiver ausente.null combinado com um hook de guarda fornece uma mensagem de erro clara quando o provider está ausente.function useTheme(): ThemeContextType {
const context = useContext(ThemeContext);
if (!context) {
throw new Error("useTheme deve ser usado dentro de ThemeProvider");
}
return context; // estreitado para ThemeContextType
}T | null para T com uma única guarda em tempo de execução.value do provider muda.{ theme, toggleTheme } cria um novo objeto a cada renderização, acionando re-renderizações.useMemo para produzir uma referência estável.AuthContext, ThemeContext) evitam re-renderizações desnecessárias.React.Dispatch<React.SetStateAction<T>>.setState(5) e setState(prev => prev + 1).createContext({} as ThemeContextType) compila, mas fornece um objeto sem propriedades reais.null + guarda é estritamente mais seguro.type AppContextType = {
state: AppState;
dispatch: React.Dispatch<AppAction>;
};
const AppContext = createContext<AppContextType | null>(null);React.Dispatch<Action> é o tipo de uma função de dispatch do useReducer.useMemo se torna excessiva.const value = useMemo<ThemeContextType>(
() => ({
theme,
toggleTheme: () => setTheme((p) => (p === "light" ? "dark" : "light")),
}),
[theme]
);
return <ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>;useMemo garante que o objeto de valor só mude quando as dependências mudarem.Revisado por Chris St. John·Última atualização: 19 de jul. de 2026
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥