MAISON CODE .
/ Tech · React · State Management · Architecture · Performance

Gestión del Estado: lo atómico versus el monolito

Redux está (casi) muerto. El contexto es una trampa. Una inmersión técnica profunda en la gestión moderna de React State: Zustand, Jotai y TanStack Query.

AB
Alex B.
Gestión del Estado: lo atómico versus el monolito

En el corazón de cada aplicación React se encuentra el “Estado”. Si la interfaz de usuario es una función del estado (€UI = f(estado)€), entonces gestionar ese estado es la decisión de ingeniería más crítica que debe tomar.

Durante años tuvimos Redux. Era detallado, centralizado e inmutable. Funcionó, pero escribiste más texto repetitivo que código. Luego tuvimos Contexto. Estaba integrado y era sencillo. Todos nos apresuramos a usarlo. Entonces nuestras aplicaciones empezaron a ralentizarse. Al escribir una entrada de texto, la barra lateral se volvió a representar. Nos dimos cuenta de que: El contexto es una herramienta de inyección de dependencias, no una herramienta de gestión de estado.

En 2025, el ecosistema habrá madurado. Ahora categorizamos el estado en tres capas distintas, cada una con una herramienta especializada.

Por qué Maison Code analiza esto

Vimos que la aplicación de un cliente se volvía a renderizar 4000 veces por segundo debido a un único proveedor de contexto. Los trasladamos a una Arquitectura estatal de tres capas:

  • Estado del servidor: consulta TanStack (para almacenamiento en caché e hidratación).
  • Estado global del cliente: Zustand (para carrito y tema).
  • Estado local: Señales o estado de uso (para entradas de formulario). Esto redujo el tiempo de bloqueo del hilo principal en 600 ms y mejoró las puntuaciones de INP a <50 ms. Creemos que la gestión del estado es la causa número uno de pérdida de rendimiento en las aplicaciones React.

La Teoría: Las Tres Capas

1. Estado del servidor (la caché)

Datos que viven en un servidor remoto. No lo “posees”; lo “tomas prestado”. Puede volverse obsoleto.

  • Ejemplos: Perfil de usuario, Lista de productos, Pedidos.
  • Herramienta: TanStack Query (React Query) o SWR.
  • Anti-Pattern: Poner datos de API en Redux/Zustand manualmente. Terminas reinventando los estados de almacenamiento en caché, deduplicación y carga.

2. Estado del cliente (la interfaz de usuario)

Datos que existen solo en el navegador y se comparten entre componentes.

  • Ejemplos: ¿Está abierto el modal? ¿Cuál es el tema actual? ¿Qué hay en el carrito de compras?
  • Herramienta: Zustand (para tiendas globales) o Jotai (para actualizaciones atómicas).

3. Estado local (el componente)

Datos aislados a un solo componente o sus hijos directos.

  • Ejemplos: ¿Está abierto el menú desplegable? ¿Cuál es el valor de este campo de entrada específico?
  • Herramienta: useState / useReducer.

El problema con el contexto

¿Por qué no utilizar createContext para todo? Debido a la Reactividad de grano grueso.

constContexto de datos = crearContexto();

función Proveedor({ niños }) {
  const [nombre, establecerNombre] = useState("Alex");
  const [tema, setTheme] = useState("Oscuro");
  
  // La referencia de este objeto cambia con CUALQUIER actualización
  valor constante = {nombre, tema, setName, setTheme}; 

  return <DataContext.Provider value={value}>{children}</DataContext.Provider>;
}

Si se llama a setName("John"):

  1. Se recrea el objeto valor.
  2. Cada componente que llama a useContext(DataContext) se vuelve a renderizar.
  3. ¡Incluso el componente ThemeToggler se vuelve a renderizar, aunque el tema no cambió!

Puedes optimizar esto con useMemo y dividir contextos (NameContext, ThemeContext), pero eso lleva al “Context Hell” (Pyramid of Doom).

La solución 1: Zustand (El reemplazo del monolito)

Zustand es más o menos “Redux sin el texto estándar”. Utiliza una arquitectura de Tienda, pero resuelve el problema de volver a renderizar con Selectores.

importar {crear} desde 'zustand';

const useStore = crear((establecer) => ({
  osos: 0,
  pez: 0,
  aumentarOsos: () => set((estado) => ({ osos: estado.osos + 1 })),
  aumentarPez: () => set((estado) => ({ pez: estado.pez + 1 })),
}));

función ContadorOso() {
  // SELECTOR: Este componente SÓLO observa 'osos'
  const osos = useStore((estado) => estado.osos);
  devolver <h1>{osos} Osos</h1>;
}

Si se llama a increaseFish(), BearCounter no vuelve a renderizarse. Zustand compara el valor de retorno del selector (state.bears). Si no ha cambiado, se salta la actualización.

Potencia del middleware

Zustand tiene principalmente un tamaño de 1 KB, pero un middleware potente. Persistir: Guarda automáticamente el estado en localStorage. Immer: permite sintaxis mutable (state.bears++) en las actualizaciones.

importar { persistir } desde 'zustand/middleware';

const useCartStart = crear(
  persistir (
    (conjunto) => ({
      elementos: [],
      addItem: (id) => set((estado) => ({ elementos: [...estado.items, id] })),
    }),
    { nombre: 'cart-storage' } // Introduce localStorage
  )
);

Acceder a componentes externos

Fundamentalmente, se puede acceder a las tiendas Zustand fuera de React (por ejemplo, en funciones de utilidad o interceptores API).

// api.ts
importar { useAuthStore } desde './authStore';

token constante = useAuthStore.getState().token; // Acceso sin gancho
fetch('/api', { encabezados: { Autorización: token } });

La Solución 2: Jotai (El Enfoque Atómico)

Jotai (inspirado en Recoil) adopta un enfoque diferente. En lugar de una gran tienda, tienes miles de pequeños átomos. El Estado se construye desde abajo.

importar {átomo, usarAtom} desde 'jotai';

// Declarar átomos
precio constanteÁtomo = átomo(10);
cantidad constanteÁtomo = átomo(2);

// Átomo calculado (derivado)
const totalAtom = atom((get) => get(priceAtom) * get(cantidadAtom));

función Carro() {
  const [total] = useAtom(totalAtom);
  devolver <div>Total: {total}</div>; 
}

Caso de uso: aplicaciones altamente interactivas como una hoja de cálculo, un editor de diagramas o un panel donde las dependencias son complejas. Si actualiza priceAtom, solo los componentes que escuchan price o total se vuelven a renderizar. Es precisión quirúrgica.

Estado del servidor: cómo lidiar con Async

Recomendamos firmemente TanStack Query. Maneja las partes difíciles del estado asíncrono:

  • Obsoleto mientras se revalida: muestra datos antiguos mientras se recuperan nuevos.
  • Enfoque de recuperación: actualiza los datos cuando el usuario regresa a la ventana.
  • Deduplicación: si 10 componentes solicitan un perfil de usuario, solo se realiza 1 solicitud de red.
const {datos, se está cargando} = useQuery({
  queryKey: ['usuario', id],
  consultaFn: () => fetchUser(id),
  staleTime: 1000 * 60, // Los datos están actualizados durante 1 minuto
});

Es común mezclar esto con Zustand. Zustand mantiene el estado de “filtro”. React Query contiene los datos de “lista” derivados de ese filtro.

Resumen: La matriz de decisiones

RequisitoRecomendación¿Por qué?
Datos APIConsulta TanStackEstados de almacenamiento en caché, deduplicación y carga integrados.
Interfaz de usuario globalZustandLos selectores simples y pequeños evitan la repetición de renderizados.
Gráfico complejoJotaiEl seguimiento de la dependencia atómica es poderoso.
Estado del formularioForma de gancho de reacciónLas entradas no controladas funcionan mejor.

10. Señales: ¿El futuro? (Preacto/Sólido)

React vuelve a renderizar componentes. Las señales (adoptadas por Preact, Solid, Vue, Angular) actualizan el DOM directamente. recuento constante = señal (0); <div>{cuenta}</div> Cuando ocurre count.value++, la función Componente NO se vuelve a ejecutar. Solo se actualiza el nodo de texto en el DOM. Esta es la complejidad O (1). React está explorando esto con “React Compiler” (Olvidar), pero las señales son una primitiva fundamentalmente más eficiente para una reactividad detallada. Seguimos de cerca este espacio. Para paneles de control de alto rendimiento (comercio de criptomonedas), a veces utilizamos Preact + Signals en lugar de React.

11. Estado persistente (local-primero)

Zustand “persistir” es simple. Pero ¿qué pasa con los datos válidos sin conexión primero? Estamos avanzando hacia el Software de prioridad local (LoFi). Herramientas como RxDB o Replicache. El “State Manager” es en realidad una base de datos local que se sincroniza en segundo plano. Esto trata al servidor como una fuente de verdad “secundaria”. El Cliente es Primario. Esta arquitectura hace que las aplicaciones se sientan instantáneas (latencia de 0 ms).

13. El patrón del observador (MobX)

Antes de Signals, existía MobX. Utiliza objetos “Observables” y “Observadores” (Componentes). Se siente como magia. Mutas un objeto user.name = "John" y el componente se actualiza. No recomendamos MobX para proyectos nuevos porque esconde demasiada complejidad (Magic Proxies). Es muy difícil depurar “¿Por qué se renderizó esto?”. Sin embargo, para aplicaciones muy específicas y con gran densidad de datos (como una hoja de cálculo), MobX es más rápido que Redux debido a su seguimiento detallado de las dependencias.

14. Redux Toolkit (RTK): la modernización

Si debes usar Redux (Enterprise Legacy), usa RTK. Se comporta como Zustand.

  • No hay declaraciones de “cambio”.
  • Immer incorporado (sintaxis mutable).
  • Consulta RTK incorporada (similar a la consulta TanStack). La migración del antiguo Redux a RTK reduce el tamaño del código en un 60%. Pero si está empezando de nuevo: Zustand es de 1 KB, RTK es de 40 KB. Elige sabiamente.

15. Honrando a los caídos: retroceso

Debemos mencionar Recoil (Meta). Inventó el concepto “Atom” para React. Pero actualmente no se mantiene (Meta se trasladó a otras herramientas internas). Jotai recogió la antorcha. Si tiene un código base de Recoil, migre a Jotai. La API es 90% similar (useRecoilState -> useAtom). No inicies nuevos proyectos con Recoil.

16. Conclusión

La gestión estatal ya no se trata de encontrar “la única biblioteca que los gobierne a todos”. Se trata de componer herramientas especializadas. En Maison Code, utilizamos de forma predeterminada la pila Zustand + React Query. Es robusto, eficaz y fácil de desarrollar.


¿Refactorizando Legacy Redux?

¿Su aplicación está enterrada bajo reductores lentos y estándar?


Contrata a nuestros Arquitectos.