CodeForge

React 19 de Cero a Experto / Estado global

Context: datos en el aire del subárbol

Teoría22 min20 XP

Context es la respuesta de React al prop drilling: te deja poner un dato "en el aire" de un subárbol —con un Provider— y que CUALQUIER descendiente lo lea directamente —con useContext—, sin props intermedias. El recado ya no pasa de mano en mano: se pone en un tablón que todos los pisos pueden consultar. Hoy lo construyes en vivo y, tan importante como usarlo, aprendes cuándo NO usarlo.

El tablón de anuncios del edificio

Los tres pasos de Context

Context tiene tres piezas: crear el contexto, proveerlo arriba, y consumirlo abajo. Aquí resolvemos el prop drilling de la lección anterior —Panel y Barra ya no tocan usuario—:

Compara con el prop drilling: Panel y Barra quedaron LIMPIOS —no reciben ni reenvían nada—. Saludo lee usuario directamente con useContext(UsuarioContext), sin importar cuántos niveles lo separen del Provider. Cambiar el usuario en App actualiza Saludo al instante (todo consumidor re-renderiza cuando el value del Provider cambia). El dato viaja "por el aire" del subárbol.

Context con estado y acciones

Lo habitual es proveer no solo un dato, sino también funciones para cambiarlo. Se agrupa en un objeto, y a menudo se envuelve en un hook propio para leerlo cómodamente:

context-con-acciones.tsx
type TemaContexto = { tema: "claro" | "oscuro"; alternar: () => void };

const TemaContext = createContext<TemaContexto | null>(null);

// hook propio: lee el contexto y avisa si falta el Provider
function useTema() {
const ctx = useContext(TemaContext);
if (ctx === null) throw new Error("useTema debe usarse dentro de <TemaProvider>");
return ctx;
}

function TemaProvider({ children }: { children: React.ReactNode }) {
const [tema, setTema] = useState<"claro" | "oscuro">("oscuro");
const alternar = () => setTema((t) => (t === "oscuro" ? "claro" : "oscuro"));
return <TemaContext.Provider value={{ tema, alternar }}>{children}</TemaContext.Provider>;
}

// cualquier descendiente:
function BotonTema() {
const { tema, alternar } = useTema();
return <button onClick={alternar}>Tema: {tema}</button>;
}

Dos buenas prácticas aquí: agrupar el valor y sus acciones en un objeto ({ tema, alternar }), y envolver useContext en un hook propio (useTema) que lanza si falta el Provider —así consumir el contexto es una línea y los errores son claros—. El Provider encapsula el estado; los consumidores solo dicen useTema().

Cuándo Context, y cuándo NO

¿Para qué tipo de datos es ideal Context y cuál es un mal uso frecuente?

Mini-reto

Construye un Context completo: 1) crea un ContadorContext que provea { cuenta, incrementar, reiniciar } (estado + acciones) desde un ContadorProvider; 2) escribe un hook useContador que lo lea y lance si falta el Provider; 3) monta dos componentes hermanos MUY separados en el árbol que usen useContador: uno muestra cuenta, otro tiene los botones. Comprueba que comparten el mismo estado sin pasarse una sola prop. Ese es el poder de Context.

Qué sigue

Context resuelve compartir datos estables. Pero para estado global que cambia seguido —o cuando quieres que solo re-rendericen los componentes que usan la parte que cambió— hay una herramienta más afilada, la favorita pragmática del ecosistema: ZUSTAND. La próxima lección la construye desde cero (sí, tu propio mini-Zustand en vivo) y luego muestra la real.