//
Busca en todas las páginas de la documentación
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥
Crea contextos React completamente tipados con createContext, proveedores tipados y hooks useContext seguros en tipos. Maneja el problema del valor por defecto de forma limpia.
// 1. Define el tipo del contexto
type Theme = "light" | "dark";
type ThemeContextType = {
theme: Theme;
toggleTheme: () => void;
};
// 2. Crea el contexto con un valor por defecto sensato o null
const ThemeContext = createContext<ThemeContextType | null>(null);
// 3. Crea un hook tipado con una guarda en tiempo de ejecución
function useTheme(): ThemeContextType {
const context = useContext(ThemeContext);
if (!context) {
throw new Error("useTheme debe usarse dentro de ThemeProvider");
}
return context;
}
// 4. Crea el componente proveedor
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. Consume en un componente
function Header() {
const { theme, toggleTheme } = useTheme();
return (
<header className={theme}>
<button onClick={toggleTheme}>Actual: {theme}</button>
</header>
);
}createContext<T>(defaultValue) crea un objeto de contexto. El genérico T define la forma del valor que los proveedores deben suministrar y los consumidores recibirán.null + hook personalizado evita dos problemas: (1) inventar un valor por defecto falso que podría enmascarar errores, y (2) obligar a los consumidores a verificar undefined en todas partes.useTheme() estrecha el tipo de ThemeContextType | null a ThemeContextType lanzando una excepción si falta el contexto. Esto proporciona a los consumidores un tipo limpio y no nulo.value del proveedor. Como { theme, toggleTheme } es un nuevo objeto en cada renderizado, envuélvelo en useMemo si tienes muchos consumidores.Contexto con useMemo para valor estable:
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últiples contextos para preocupaciones 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 debe usarse dentro de AuthProvider");
return context;
}Contexto con 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>> es el tipo de un setter de useState. Úsalo en tipos de contexto cuando expongas un setter directamente.React.Dispatch<Action> es el tipo de una función dispatch de useReducer.as para hacer casting del valor por defecto: createContext({} as ThemeContextType) se compila pero proporciona un objeto inválido en tiempo de ejecución si falta el proveedor.createContext({} as T) silencia TypeScript pero conduce a bloqueos en tiempo de ejecución cuando falta el proveedor. El patrón null + guard es más seguro.value en cada renderizado causa que todos los consumidores se re-rendericen. Usa useMemo para el objeto de valor.useTheme, useAuth) es crítico para una buena experiencia de desarrollador. Sin él, los consumidores deben importar tanto el contexto como useContext, y manejar null ellos mismos.| Enfoque | Ventajas | Desventajas |
|---|---|---|
null default + guard hook | Seguro en tipos, error claro en mal uso | Requiere hook personalizado por contexto |
Non-null assertion ({} as T) | Sin verificaciones de null necesarias | Bloqueo en tiempo de ejecución si falta el proveedor |
| Valor por defecto real | Funciona sin proveedor | Debes inventar un valor por defecto significativo |
| Zustand o Jotai | API más simple, suscripciones de grano fino | Dependencia externa |
| Estado a nivel de módulo | Sin anidamiento de proveedor | No es reactivo, no es seguro para SSR |
createContext({} as T) proporciona un objeto inválido que silenciosamente causa bloqueos en tiempo de ejecución si falta el proveedor.null combinado con un hook de guarda proporciona un mensaje de error claro cuando falta el proveedor.function useTheme(): ThemeContextType {
const context = useContext(ThemeContext);
if (!context) {
throw new Error("useTheme debe usarse dentro de ThemeProvider");
}
return context; // estrechado a ThemeContextType
}T | null a T con una única guarda en tiempo de ejecución.value del proveedor.{ theme, toggleTheme } crea un nuevo objeto en cada renderizado, lo que provoca re-renderizaciones.useMemo para producir una referencia estable.AuthContext, ThemeContext) previenen re-renderizaciones innecesarias.React.Dispatch<React.SetStateAction<T>>.setState(5) y setState(prev => prev + 1).createContext({} as ThemeContextType) se compila pero proporciona un objeto sin propiedades reales.null + guard es estrictamente más seguro.type AppContextType = {
state: AppState;
dispatch: React.Dispatch<AppAction>;
};
const AppContext = createContext<AppContextType | null>(null);React.Dispatch<Action> es el tipo de una función dispatch de useReducer.useMemo se vuelve excesiva.const value = useMemo<ThemeContextType>(
() => ({
theme,
toggleTheme: () => setTheme((p) => (p === "light" ? "dark" : "light")),
}),
[theme]
);
return <ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>;useMemo asegura que el objeto de valor solo cambia cuando cambian las dependencias.Revisado por Chris St. John·Última actualización: 19 jul 2026
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥