Saltar al contenido principal

Estado compartido: el problema que resuelve un store

En la semana 12 construimos un login con useState, guardamos el token en localStorage y protegimos las rutas con un AuthGuard. Funciona, pero cada pantalla que necesita saber quién es el usuario tiene que leer localStorage por su cuenta, y ningún componente se entera cuando la sesión cambia.

Antes de instalar cualquier librería conviene entender el problema con precisión. Una herramienta de estado se elige bien solo cuando sabes qué dolor te quita. En esta lección vamos de lo más simple (useState) hasta el punto donde un store global deja de ser un lujo.


1. Qué es el estado​

El estado (state) es la información que cambia con el tiempo y de la que depende lo que ves en pantalla. Cuando el estado cambia, React vuelve a dibujar la interfaz.

No todo el estado es del mismo tipo, y mezclarlos es la fuente de la mayoría de los enredos:

TipoEjemplo en nuestra appDónde conviene vivir
Local de un componenteTexto escrito en el input del login, si un menú está abiertouseState dentro del componente
Compartido entre componentesUsuario autenticado, notificaciones, carrito, tema visualUn store (lo que veremos esta semana)
Del servidor (server state)Lista de usuarios que devuelve GET /usersUna capa de datos (fetch, caché); no es lo mismo que el estado de UI
De la URLFiltros de búsqueda, página actual, id de la rutaLa propia URL (searchParams, params)
Regla práctica

Empieza siempre con el estado más local posible. Súbelo solo cuando dos componentes que no son padre e hijo necesiten el mismo dato.


2. Cómo viaja el estado en React​

Recorre el árbol de componentes de una página. Verás dónde vive el estado, cómo se sube al ancestro común (lifting state up), por qué aparece el prop drilling y qué logra (y qué no) Context.

Cómo viaja el estado por el árbol de componentes

Lo esencial de ese recorrido:

  1. Los datos solo bajan por el árbol (de padre a hijo, como props). No hay un camino lateral entre ramas.
  2. Subir el estado al ancestro común resuelve el primer problema, pero obliga a pasar props por componentes que no las usan (prop drilling).
  3. Context da un salto directo, pero cuando cambia su value se vuelven a renderizar todos los consumidores, aunque solo les interese una parte.

3. Un problema concreto: la sesión del usuario​

Piensa en la aplicación del caso de estudio de la semana 12. Necesitan la sesión:

  • El AuthGuard, para decidir si deja entrar.
  • La barra de navegación, para mostrar el nombre y el botón "Cerrar sesión".
  • El dashboard, para pedir GET /users con el token.
  • Cualquier formulario que firme una petición.

Con lo que sabemos hasta ahora hay tres salidas, todas con costo:

Tres formas de compartir la sesión
// 1. Props: el dato baja por todos los intermedios (prop drilling)
<AppLayout user={user}>
<Navbar user={user} /> {/* Navbar solo lo reenvía */}
</AppLayout>

// 2. Context: un Provider y useContext, pero todo consumidor se re-renderiza
<AuthContext.Provider value={{ user, token, login, logout }}>
<App />
</AuthContext.Provider>

// 3. localStorage directo (lo que hicimos en la semana 12): nadie se entera del cambio
const token = session.getToken();

Ninguna es incorrecta. Lo que pasa es que a medida que la app crece, cada una acumula deuda: props repetidas, re-renders que no se ven, o pantallas que no se actualizan cuando cierras sesión en otra parte de la app.


4. Qué es un store global​

Un store es un objeto que vive fuera del árbol de componentes y que guarda dos cosas juntas:

  1. El estado compartido (user, token, notifications).
  2. Las acciones que lo modifican (login(), logout(), addNotification()).

Cualquier componente se suscribe a la parte que le interesa y React lo vuelve a dibujar solo cuando esa parte cambia.

Analogía: el tablero de anuncios de la facultad. Cualquiera puede ir a leer el aviso que le importa, y cuando coordinación cambia un aviso, solo se entera quien estaba mirando ese aviso. Nadie le lleva el papel de mano en mano a cada salón.

Lo que cambia frente a lo anterior:

AntesCon un store
El dato baja por propsEl componente lo lee directo del store
El cambio sube por callbacksEl componente llama la acción del store
Context re-renderiza a todosCada componente se suscribe solo a lo que usa (selectores)
El estado vive en el árbolEl estado vive afuera, sobrevive a que un componente se desmonte

Cuándo NO hace falta​

Un store global no es la respuesta a todo. No lo uses para:

  • El valor de un input mientras el usuario escribe (es estado local).
  • Datos que vienen del servidor y se vuelven a pedir en cada pantalla (eso es server state; un store puede guardarlos, pero no sustituye una estrategia de caché).
  • Algo que solo usan un componente y sus hijos directos.

5. Mapa de la semana​

Esta semana recorremos el camino en este orden:

1

Concepto: el store y su flujo

Qué es Zustand, cómo se ve un store, qué es set, qué es un selector y cómo se compara con Redux y Context. Ver Conceptos de Zustand.

2

Configuración en Next.js

Instalación, tipado con TypeScript, ubicación del store por feature, 'use client' y el cuidado con el servidor. Ver Configuración de Zustand.

3

Capacidades

Selectores, useShallow, acciones asíncronas, middleware (devtools, persist, immer) y uso fuera de React. Ver Capacidades de Zustand.

4

Caso práctico

Migramos la sesión de la semana 12 a un store con persistencia y construimos un sistema de notificaciones. Ver Caso práctico.


Cuestionario de Autoevaluación​

Cargando cuestionario...