Contexto, Estado o Redux Toolkit: Elija según la complejidad de la transición
Elija las herramientas de estado de React según la complejidad de las transiciones, no según el tamaño de la aplicación: Context propaga las dependencias en forma de árbol, Zustand agiliza las suscripciones, y Redux Toolkit modela las transiciones.
Fuentes: Vibe Coding Can Build the Store. Can You Design It?
La IA ha hecho que una parte del trabajo en el frontend sea casi gratuita: la generación del código. Si se solicita un almacén Zustand, una porción Redux o Context junto con useReducer, un modelo emitirá algo que se pueda compilar. La sintaxis ya no es la parte difícil; lo complicado es tener un boceto arquitectónico vacío y decidir cómo debe circular el estado dentro del producto.
Ese es el verdadero problema de gestión de estados. Context API, Zustand y Redux Toolkit abordan este problema desde direcciones diferentes. Lo importante aquí no son detalles menores sobre las API, sino lo que hay detrás de ellas.
1. Context API: el árbol de React es el límite
Context responde a una pregunta concreta: ¿cómo puede un valor llegar hasta componentes profundos sin tener que pasar por cada capa mediante propiedades?
La documentación de React describe useContext como una forma de leer y escuchar un contexto. Un componente toma el valor del proveedor más cercano que se encuentre por encima de él. Cuando el valor de ese proveedor cambia, los lectores se actualizan.
Lo importante no es la llamada al hook, sino la relación en forma de árbol.
El proveedor define un entorno; el consumidor lee de él.
El contexto existe dentro de la jerarquía de React.
El contexto no gestiona el estado por sí solo
Un error común es pensar que Context es una biblioteca para manejar estado. Las actualizaciones suelen provenir de useState, reducers o hooks personalizados. El contexto principalmente propaga el valor que generan esos hooks.
La gran trampa del contexto
La gente dice “El contexto provoca recálculos innecesarios”. Ese eslogan es demasiado simplista. React compara el value anterior y posterior del proveedor con Object.is. Cuando el valor cambia, todos los lectores se actualizan; un límite memo no impide que llegue un contexto nuevo.
Considere un único conjunto de campos no relacionados:
<AppContext
value={{
user,
cart,
orders,
notifications
}}
>
El problema real es de tipo arquitectónico: existe un único límite de dependencia amplio para dominios que no deberían estar relacionados.
En lugar de:
AppContext
prefiera:
AuthContext
ThemeContext
FeatureFlagContext
Cada contexto tendrá entonces una función semántica clara. Regla de diseño: un contexto debe representar un límite de dependencia significativo. El problema no es el contexto en sí a gran escala, sino más bien un contexto enorme.
2. Abandonar el árbol: Zustand
El contexto está vinculado al árbol de componentes. Zustand plantea una pregunta diferente: ¿cómo puede el estado del cliente compartido existir fuera de ese árbol con suscripciones precisas?
Un almacén puede contener el estado y las funciones que lo modifican:
const useCartStore = create((set) => ({
items: [],
addItem: (item) =>
set((state) => ({
items: [...state.items, item]
})),
removeItem: (id) =>
set((state) => ({
items: state.items.filter(
item => item.id !== id
)
}))
}));
Los componentes seleccionan partes específicas del estado:
const items = useCartStore(
state => state.items
);
La ventaja radica en el Límite de suscripción. El componente no solicita todo el almacén; solo pide la parte que le interesa. Los selectores hacen explícito ese contrato.
Por qué sigue apareciendo Redux
Si Zustand es tan sencillo, ¿por qué existe Redux Toolkit? Porque el problema deja de ser “¿dónde debo colocar este valor?” y pasa a ser “¿cómo puedo manejar todo lo que puede modificarlo?”
Imagínese dominios que se superponen:
Checkout
Payment
Inventory
Orders
Refunds
Permissions
Un flujo de trabajo podría verse así:
Checkout Started
↓
Payment Started
↓
Payment Succeeded
↓
Inventory Reserved
↓
Order Created
Si la reserva de inventario falla después de que el pago tenga éxito, el problema ya no es de almacenamiento, sino un problema de transición de estado. Ahí es donde la estructura de Redux resulta útil.
3. Redux como transiciones explícitas
Un enfoque útil no es pensar que “Redux es un almacén global”. Considéralo como un sistema explícito para describir eventos y calcular estados siguientes predecibles:
nextState =
reducer(previousState, action)
Flujo de Redux
Junto con una línea simple como set(...), esto parece complicado:
set(...)
Cada paso sigue teniendo una función específica:
- Acción — ¿qué ocurrió?
- Reductor — ¿cómo debe cambiar el estado?
- Almacén — ¿cuál es el estado actual?
- Selector — ¿qué necesita este componente?
Esa claridad es la característica distintiva. Cuando las reglas de negocio se complican, saber por qué cambió el estado puede ser más útil que guardar diez líneas de código.
Redux Toolkit es el Redux moderno
Redux clásico requería tipos de acciones manuales y creadores de acciones. Toolkit simplifica esto con createSlice:
const cartSlice = createSlice({
name: "cart",
initialState: {
items: []
},
reducers: {
addItem(state, action) {
state.items.push(action.payload);
}
}
});
El estado relacionado y las transiciones permanecen juntos; se generan los creadores de acciones. Immer permite una sintaxis similar a la de las mutaciones mientras produce actualizaciones inmutables. El Redux moderno implica menos “escritura de código genérico” y más “mantenimiento de un modelo de transiciones estructurado sin las formalidades históricas”.
Middleware y operaciones asíncronas
El middleware se encuentra entre dispatch y reduce:
Ese espacio es donde se encuentran la registro de actividades, el análisis de datos, los flujos de trabajo asíncronos y las reacciones a acciones específicas. Toolkit añade herramientas como createAsyncThunk y middleware de escucha. Zustand deja la organización asíncrona abierta; Toolkit ofrece patrones más consolidados.
¿Cuál elegir?
Evite la heurística del tamaño:
- Aplicación pequeña → Context
- Mediana → Zustand
- Grande → Redux
La cantidad de pantallas no es un buen indicador de la complejidad del estado. Una aplicación CRUD con cien pantallas puede ser más simple que un flujo de pagos y permisos con diez pantallas.
Prefiera pensar en relaciones y transiciones:
Modelo mental a mantener
No memorice tres logotipos. Recuerde tres enfoques:
- Context — distribuir una dependencia a través del árbol de React
“¿Cuál es la mejor biblioteca?” es la primera pregunta incorrecta. Mejor preguntarse: ¿qué tipo de complejidad se necesita gestionar? Elija la abstracción que haga más fácil comprender esa complejidad, no aquella etiquetada como “moderna”.
En la práctica, muchos conjuntos de código combinan estas herramientas: Context para temas y configuración regional, Zustand para carritos de compras y elementos visuales de la interfaz, y Toolkit únicamente cuando flujos multietapa relacionados con dinero e inventario requieren un registro de auditoría. Esa combinación funciona bien siempre que cada límite esté definido intencionalmente. Los problemas surgen cuando un único mega-contexto o un almacén no diferenciado absorbe todas las funcionalidades porque alguna sugerencia indicó usar una sola biblioteca para todo.
Lecturas relacionadas
- Contexto vs Redux Toolkit vs Zustand para el state de React — Compare Context, Redux Toolkit y Zustand para un portal de videos, y luego combine las tiendas del cliente con TanStack Query para el state del servidor.
- Zustand en la práctica: Tiny Stores, Selectores Afilados, Rastreador de Plantas — Reemplace el uso de prop-drilling y las complejidades de Redux con create(), selectores, acciones asíncronas, middleware persist/devtools, slices y una aplicación de rastreo de plantas.