Mueve datos sin prop drilling usando el context, manteniendo bajo control sus re-renders y sus límites.
Abrir esta lección en KodokonEl prop drilling se refiere a esas props que atraviesan tres o cuatro componentes intermedios sin usarse en ellos, solo para llegar a una hoja del árbol. Cada capa que cruzan queda acoplada a datos que no le interesan. El context resuelve este problema de transporte: createContext crea el canal, un provider publica un valor y useContext lo lee desde cualquier descendiente. Ten presente el matiz: el context transporta el estado, no lo gestiona - el valor sigue viviendo en un componente, aquí el provider.
import { createContext, useMemo, useState } from "react";
const ThemeContext = createContext(null);
function ThemeProvider({ children }) {
const [theme, setTheme] = useState("dark");
const value = useMemo(
() => ({ theme, setTheme }),
[theme]
);
return (
<ThemeContext.Provider value={value}>
{children}
</ThemeContext.Provider>
);
}Cuando el valor del provider cambia, todos los consumidores vuelven a renderizarse, incluso los que están muy anidados - y React.memo no los protege, porque compara props, no el context. La trampa clásica lo empeora: escribir value={{ theme, setTheme }} crea un objeto nuevo en cada render del provider, de ahí una nueva referencia, de ahí re-renders en cascada aunque theme no se haya movido. Para eso sirve el useMemo anterior. Completa la configuración con un hook de acceso que falle ruidosamente fuera del provider.
import { useContext } from "react";
function useTheme() {
const context = useContext(ThemeContext);
if (context === null) {
throw new Error(
"useTheme must be inside <ThemeProvider>"
);
}
return context;
}Antes de crear un context, agota primero la opción de la composición. Si una capa intermedia no hace más que retransmitir una prop, invierte la estructura: construye el elemento en la cima del árbol, donde viven los datos, y pásalo hacia abajo mediante children o una prop dedicada. La capa intermedia se vuelve genérica y los datos ya no pasan por ningún componente que no los use.
function App({ currentUser }) {
return (
<Layout
header={<TopBar user={currentUser} />}
content={<Dashboard />}
/>
);
}