Estado de aplicación en React

La pregunta no es «qué librería de estado usar», sino qué representa el dato, quién lo necesita y cuál es su fuente de verdad. Elegir la ubicación correcta reduce sincronizaciones, efectos y cachés manuales.

Clasifica el dato antes de guardarlo

TipoEjemplosLugar inicialSeñal de que debe subir
Estado de interfaz localmodal abierto, input controlado, pestaña activauseState en el componenteun hermano o ancestro también debe modificarlo
Estado compartido del clientepreferencias de UI, carrito local, usuario ya cargadoancestro común; Context si atraviesa varias capasactualizaciones frecuentes o dominios complejos
Estado de URLbúsqueda, página, ordenación, filtroparámetros de ruta o query stringdebe sobrevivir a recarga, historial o enlace compartible
Estado persistido en navegadortema, borrador no sensiblelocalStorage o cookie de preferenciase necesita entre sesiones, no en el servidor
Estado de servidorlista remota, perfil, permisos, saldocaché/consulta de datos, por ejemplo Tanstack Queryhay revalidación, errores, carga o invalidación

No copies un estado de servidor a useState solo para mostrarlo: crea dos fuentes de verdad y obliga a sincronizarlas. Deriva los valores que puedas durante el renderizado y conserva solo el mínimo dato editable.

Secuencia de decisión

  1. ¿Solo un componente lo lee y modifica? Empieza con React useState.
  2. ¿Debe aparecer en un enlace, usar el botón Atrás o poder compartirse? Llévalo a la URL.
  3. ¿Procede de una API o base de datos? Mantén el dato en una capa de consulta y sincronización; no en un store global por defecto.
  4. ¿Varios componentes del mismo árbol lo necesitan? Eleva el estado al ancestro común. React Context es apropiado para datos relativamente estables que muchos descendientes consumen.
  5. ¿Debe sobrevivir a cerrar el navegador? Persiste únicamente preferencias o borradores no sensibles con useLocalStorage o una cookie. La sesión y los secretos los controla el servidor.

Ejemplo: filtro compartible

Un término de búsqueda que solo sirve para una vista puede empezar local. Cuando el enlace debe preservar el filtro, la URL es la fuente de verdad:

const params = new URLSearchParams(window.location.search);
const query = params.get("q") ?? "";
 
function updateQuery(next: string) {
  params.set("q", next);
  window.history.replaceState(null, "", `?${params}`);
}

En un framework, usa su API de router para que la navegación y el renderizado permanezcan coordinados. El ejemplo ilustra la decisión de modelado, no sustituye el manejo de rutas de NextJS o Remix.

Límites y errores habituales

  • Context no reemplaza una caché de servidor: una actualización puede rerenderizar a muchos consumidores y no resuelve reintentos, invalidación ni datos obsoletos.
  • localStorage es accesible desde JavaScript. No guardes tokens, credenciales ni información privada.
  • Una cookie con HttpOnly no se lee desde React por diseño; es la opción adecuada para sesiones que debe gestionar el servidor.
  • Evita efectos que copian un valor derivable. Por ejemplo, calcula items.filter(...) en renderizado antes de crear otro estado para la lista filtrada.

Relacionado

Fuentes