¡Compártelo!

State management en frontend: Redux, Zustand o Context API

Gestionar el estado en aplicaciones React modernas o el state management puede ser un desafío, especialmente cuando la app crece y los datos se comparten entre muchos componentes. En este artículo, vamos a explicar cuáles son los conceptos clave de la gestión de estado y luego analizaremos tres soluciones populares: Redux, Zustand y Context API, explorando sus arquitecturas, patrones de diseño y casos de uso recomendados. 

El objetivo será explicar no sólo con ejemplos de casos, si no también dar una idea de lo qué está pasando detrás de cada librería y cómo usarla correctamente

Conceptos clave de gestión de estado 

Antes de entrar en las librerías, es importante entender los elementos:

Estado (State) 

El estado es toda la información que define la apariencia y el comportamiento de la aplicación en un momento dado. Por ejemplo, un contador, un tema de color o la lista de productos en un carrito

type CounterState = { count: number }; 
const state: CounterState = { count: 0 }; 

Acción (Action)

Una acción es un objeto que describe qué cambio queremos hacer en el estado. En Redux, por ejemplo:

interface IncrementAction { 
 type: 'counter/increment'; 
 payload: { amount: number }; 
} 

const incrementAction: IncrementAction = { type: 'counter/increment', payload: { amount: 5 } }; 

Piénsalo como un mensaje que le dice a tu app qué hacer, pero no lo hace directamente.

Reducer 

Un reducer es una función pura que recibe el estado actual y una acción, y devuelve un nuevo estado. Nunca modifica el estado original. 

function counterReducer(state: CounterState = { count: 0 }, action: IncrementAction): CounterState { 
 switch(action.type) { 
 case 'counter/increment': 
 return { count: state.count + action.payload.amount }; 
 default: 
 return state; 
 } 
} 

Analogía: el reducer es un juez imparcial que decide cómo cambia el estado según la acción recibida.

Store 

El store es el contenedor central del estado. En Redux es único; en Zustand puedes tener varios si quieres separar responsabilidades.

import { configureStore } from '@reduxjs/toolkit'; 
const store = configureStore({ reducer: counterReducer }); 

Provider 

En Context API, un Provider es un componente que proporciona el estado a todos los componentes hijos que lo necesiten. 

import React, { createContext, useContext } from 'react'; 
const ThemeContext = createContext<string>('light'); 
<ThemeContext.Provider value="dark"> 
 <App /> 
</ThemeContext.Provider>; 

Selector 

Un selector es una función que elige solo la parte del estado que necesita un componente, evitando renders innecesarios.

const count = useStore((state: CounterState) => state.count);

Redux: Arquitectura Flux y Predictibilidad

Fundamentos Arquitectónicos 

Redux se basa en Flux, con un flujo de datos unidireccional

Principios clave: 

  1. Una única fuente de verdad: un solo store. 
  2. Estado de solo lectura: cambios solo mediante acciones. 
  3. Reducers puros: devuelven un nuevo estado sin modificar el original.
import { configureStore, createSlice, PayloadAction } from '@reduxjs/toolkit'; 
interface CounterState { count: number; } 
const counterSlice = createSlice({ 
 name: 'counter', 
 initialState: { count: 0 } as CounterState, 
 reducers: { 
 increment: (state, action: PayloadAction<number>) => { state.count += action.payload; }, 
 }, 
}); 
const store = configureStore({ reducer: counterSlice.reducer }); 

Patrones de Diseño 

  • Singleton: Un único store global. 
  • Command: Las acciones encapsulan cambios. 
  • Observer (Pub/Sub): Los componentes se suscriben a cambios.
  • Reducer (Fold): Función pura para transformar estado. 

Características Distintivas 

Características Distintivas Redux

Context API: Solución Nativa de React

Fundamentos Arquitectónicos 

Context API permite compartir datos sin prop drilling. Se basa en la composición de React y proporciona Providers y Consumers.

const ThemeContext = createContext<'light' | 'dark'>('light');
function App() {
const theme = useContext(ThemeContext);
return <div className={theme}>Hola mundo</div>;
}

Patrones de Diseño

  • Provider-Consumer: el Provider comparte, el Consumer consume.
  • Dependency Injection: inyecta estado y funciones en componentes hijos.
  • No es Singleton: puedes tener varios Providers del mismo contexto.

Características Distintivas

Características Distintivas Context API

Zustand: Minimalismo y Pragmatismo

Fundamentos Arquitectónicos

Zustand ofrece hooks para manejar el estado de manera simple y eficiente.

import create from 'zustand';
interface CounterState { count: number; increment: () => void; } 
const useStore = create<CounterState>((set) => ({ 
 count: 0, 
 increment: () => set((state) => ({ count: state.count + 1 })), })); 
function Counter() { 
 const count = useStore((state) => state.count); 
 const increment = useStore((state) => state.increment); 
 return <button onClick={increment}>{count}</button>; 
} 

 Patrones de Diseño 

  • Singleton opcional 
  • Flux simplificado 
  • Module pattern 
  • Selective subscription para evitar renders innecesarios.

Características Distintivas 

Características Distintivas zustand

Análisis Comparativo

Análisis Comparativo Redux, Zustand y Context API

Consideraciones de Rendimiento 

  • Redux: optimización con React.memo, useSelector y memorización (Reselect). 
  • Context API: vulnerable a re-renders excesivos; se mejora con múltiples contextos o useMemo. 
  • Zustand: Suscripción granular evita re-renders innecesarios de forma nativa. 

Casos de Uso Recomendados 

  • Redux: apps complejas, auditables y con middleware sofisticado. 
  • Context API: apps pequeñas/medianas con estado simple. 
  • Zustand: apps modernas que buscan simplicidad y performance. 

Patrones Arquitectónicos Transversales

Inmutabilidad 

  • Redux: obligatoria. 
  • Context API / Zustand: recomendada. 

Separación de Responsabilidades 

  • Redux: actions + reducers .
  • Context API: custom hooks. 
  • Zustand: stores modulares.

Testabilidad 

  • Redux: muy fácil (funciones puras). 
  • Zustand: fácil (stores independientes). 
  • Context API: más difícil (necesita renderizar Providers).

Conclusiones 

No hay una solución perfecta. La elección depende del tamaño de la app, equipo y necesidades de rendimiento

  • Redux: robustez y ecosistema maduro para apps grandes. 
  • Context API: simple y nativo, perfecto para casos limitados. 
  • Zustand: minimalista, potente y fácil de usar. 

La tendencia apunta a soluciones ligeras como Zustand, priorizando la developer experience sin sacrificar capacidad técnica, aunque Redux sigue siendo relevante en entornos empresariales. 

 Si te interesa estar al día en desarrollo web, arquitectura y buenas prácticas en programación, síguenos en nuestras redes sociales y Canal de YouTube.

Referencias 
  • Abramov, D. (2015). Redux: Predictable state container for JavaScript apps
  • Facebook Inc. (2019). React Context API Documentation 
  • Dai, D. (2023). Zustand: Bear necessities for state management
  • Gamma, E. et al. (1994). Design Patterns: Elements of Reusable Object-Oriented Software

Artículos ​ relacionados