Context API y Estado Global
Volver a clases
Frontend Development●●Intermedio

Context API y Estado Global

120 min

Crear contextos, providers y combinar con useReducer.

Context básico

  • createContext crea un contenedor de datos.
  • Provider envuelve la app y comparte el estado.
  • useContext consume la información.
  • Conviene definir un valor inicial y un custom hook para simplificar el consumo.
  • Si el contexto es obligatorio, lanzar error si se usa fuera del Provider.

¿Cuándo usar Context?

  • Para datos globales reales: tema, auth, idioma, permisos, carrito.
  • Evita usarlo para estados muy locales; puede generar renders innecesarios.
  • Si solo dos componentes comparten datos, props puede ser mas simple.

Composición de providers

  • Se pueden anidar multiples providers en un componente AppProviders.
  • Ayuda a mantener main.jsx limpio y ordenado.
  • Prioriza providers con menos cambios arriba para evitar renders masivos.

Context para autenticación

  • Centraliza login, logout y usuario actual.
  • Permite proteger rutas con la misma fuente de verdad.
  • Guarda el estado de "cargando" mientras valida sesion.
  • Puede incluir roles/permisos para habilitar secciones.

Context + useReducer

  • Útil para estados complejos como un carrito.
  • La lógica se organiza por acciones.
  • Define un initialState y acciones claras (ADD, REMOVE, UPDATE).
  • Mantener el reducer puro facilita testing y depuracion.

Buenas prácticas y rendimiento

  • Separa contextos por dominio para evitar renders globales.
  • Memoiza el value del Provider cuando depende de objetos.
  • Evita pasar funciones inline que cambien en cada render.

El criterio: ¿Context o props?

"Usa Context" es la respuesta que la IA da a casi cualquier problema de datos compartidos, porque le evita pensar el árbol de componentes. El criterio real:

SituaciónHerramienta
El dato tiene un destino conocido, aunque esté hondoComposición con children (lo viste en props)
El dato es transversal y lo consumen muchos puntos imprevisiblesContext
Solo dos componentes hermanos lo compartenEstado en el padre común + props

La señal práctica de que llegó el momento de Context: cada vez que agregas un consumidor nuevo tienes que volver a cablear componentes intermedios que no usan el dato, y eso pasa seguido. Los casos legítimos son pocos y conocidos: sesión del usuario, tema visual, idioma, carrito.

Context no es "estado global mágico": es un cable para evitar el prop drilling. No reemplaza al estado ni te da persistencia.

La trampa del value que siempre cambia

Este es el error de rendimiento más común con Context, y es sutil:

jsx
1// ❌ objeto NUEVO en cada render del Provider
2<AuthContext.Provider value={{ usuario, login, logout }}>

Cada render del Provider crea un objeto nuevo. Para React eso es un valor distinto, así que todos los consumidores se re-renderizan, aunque usuario no haya cambiado. En una app chica no se nota; con un contexto que consumen 20 componentes, sí.

jsx
1// ✅ la referencia solo cambia cuando cambia lo que importa
2const value = useMemo(
3  () => ({ usuario, login, logout }),
4  [usuario, login, logout]
5);
6
7<AuthContext.Provider value={value}>

(Para que login y logout sean estables a su vez, se declaran con useCallback dentro del Provider.)

El custom hook que blinda el consumo

En vez de que cada componente haga useContext(AuthContext), se expone un hook propio que además falla ruidosamente si alguien lo usa fuera del Provider:

jsx
1export function useAuth() {
2  const ctx = useContext(AuthContext);
3  if (ctx === undefined) {
4    throw new Error("useAuth debe usarse dentro de <AuthProvider>");
5  }
6  return ctx;
7}

Sin esa verificación, usarlo fuera del Provider devuelve undefined y truena después, en otra línea, con un mensaje que no dice nada. Un error claro en el momento correcto vale más que diez horas de depuración — es el mismo principio del "error silencioso" de la Auditoría IA #2.

Ejemplos de Código

3 ejemplos

Context básico

javascript
1import { createContext, useContext, useState } from "react";
2
3const ThemeContext = createContext();
4
5export function ThemeProvider({ children }) {
6  const [theme, setTheme] = useState("light");
7  const toggleTheme = () => setTheme((t) => (t === "light" ? "dark" : "light"));
8
9  return (
10    <ThemeContext.Provider value={{ theme, toggleTheme }}>
11      {children}
12    </ThemeContext.Provider>
13  );
14}
15
16export function useTheme() {
17  return useContext(ThemeContext);
18}

Auth con Context

javascript
1import { createContext, useContext, useEffect, useState } from "react";
2
3const AuthContext = createContext();
4
5export function AuthProvider({ children }) {
6  const [user, setUser] = useState(null);
7
8  useEffect(() => {
9    const saved = localStorage.getItem("user");
10    if (saved) setUser(JSON.parse(saved));
11  }, []);
12
13  const login = (userData) => {
14    setUser(userData);
15    localStorage.setItem("user", JSON.stringify(userData));
16  };
17
18  const logout = () => {
19    setUser(null);
20    localStorage.removeItem("user");
21  };
22
23  return (
24    <AuthContext.Provider value={{ user, login, logout }}>
25      {children}
26    </AuthContext.Provider>
27  );
28}
29
30export function useAuth() {
31  return useContext(AuthContext);
32}

Reducer global

javascript
1import { createContext, useContext, useReducer } from "react";
2
3const CartContext = createContext();
4
5function reducer(state, action) {
6  switch (action.type) {
7    case "ADD":
8      return { ...state, items: [...state.items, action.payload] };
9    case "CLEAR":
10      return { ...state, items: [] };
11    default:
12      return state;
13  }
14}
15
16export function CartProvider({ children }) {
17  const [state, dispatch] = useReducer(reducer, { items: [] });
18
19  return (
20    <CartContext.Provider value={{ state, dispatch }}>
21      {children}
22    </CartContext.Provider>
23  );
24}
25
26export function useCart() {
27  return useContext(CartContext);
28}

Recursos

3 recursos disponibles

¡Hora de Practicar!

PrácticaIntermedio15 min🟡 IA con bitácora

Práctica guiada - Theme + Auth

Práctica

Implementar tema claro/oscuro y login con Context.

Desafío de Código

EjercicioIntermedio15 min🔴 Sin IA

Ejercicios - Carrito global

Ejercicios

(1) Agregar items, (2) eliminar items, (3) total acumulado.

Documentación Oficial

DocumentaciónIntermedio15 min

Context API

Guía oficial de Context en React.