El manejo de estado en aplicaciones React es un desafío recurrente. Librerías como Redux o Redux Toolkit ofrecen soluciones robustas pero, en muchos casos, demasiado complejas para necesidades simples. Zustand emerge como una alternativa moderna, liviana y extremadamente intuitiva.
En este artículo te guiaré desde qué es Zustand, sus ventajas sobre otras opciones, hasta cómo implementar un contador utilizando middlewares como persist
y devtools
, e incluso integrar validaciones con Zod.
¿Qué es Zustand?
Zustand ("estado" en alemán) es una librería minimalista de manejo de estado para aplicaciones React. Fue creada por Poimandres (los mismos de jotai
y react-three-fiber
) y ofrece una API pequeña pero extremadamente poderosa.
Algunas características principales:
- No depende del árbol de componentes.
- No requiere boilerplate.
- Trabaja de forma reactiva pero es independiente de React internamente.
- Permite middlewares para persistencia, devtools, entre otros.
Comparación con Otras Soluciones
Característica | Redux | Redux Toolkit | Zustand |
---|---|---|---|
Boilerplate | Muy Alto | Moderado | Muy Bajo |
API | Verbosa | Simplificada | Muy simple |
Curva de Aprendizaje | Alta | Media | Muy Baja |
Integración Devtools | Manual + Configuración extra | Integración automática | Sencilla y directa |
Persistencia de Estado | Requiere configuración manual | Requiere middlewares adicionales | Integrado vía middleware |
Uso fuera de componentes | Difícil | Más sencillo pero no nativo | Muy fácil |
Tamaño de la librería | Grande | Medio | Pequeño (~1KB gzipped) |
Como puedes observar, Zustand es ideal para quienes buscan una solución directa, moderna y altamente eficiente, mientras que Redux Toolkit representa una mejora significativa sobre Redux clásico, pero aún mantiene cierta complejidad estructural.
Creando un Store de Contador con Zustand
Primero, instalemos Zustand:
npm install zustand
Ahora, creamos el store:
// src/stores/counterStore.ts
import { create } from 'zustand'
interface CounterState {
count: number
increment: () => void
decrement: () => void
reset: () => void
}
export const useCounterStore = create<CounterState>((set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
decrement: () => set((state) => ({ count: state.count - 1 })),
reset: () => set({ count: 0 }),
}))
Notas importantes:
- El nombre
useCounterStore
sigue la convención de React Hooks. - El store debe estar fuera de los componentes para ser compartido globalmente.
Usando el Store en un Componente
// src/components/Counter.tsx
import { useCounterStore } from '../stores/counterStore'
const Counter = () => {
const { count, increment, decrement, reset } = useCounterStore()
return (
<div>
<h1>{count}h1>
<button onClick={increment}>Incrementarbutton>
<button onClick={decrement}>Decrementarbutton>
<button onClick={reset}>Resetearbutton>
div>
)
}
export default Counter
Con esto tienes un contador funcional, sin necesidad de reducers, actions ni context providers.
Agregando Persistencia y Devtools
Zustand permite utilizar middlewares para ampliar funcionalidades.
Lo primero que debemos hacer es instalar la extensión Redux DevTools de Chrome para utilizar el middleware devtools.
import { devtools } from 'zustand/middleware'
// Envolvemos todo nuestro store con devtools
const usePlainStore = create(devtools((set) => ...))
Modificamos el store:
import { create } from 'zustand'
import { devtools, persist } from 'zustand/middleware'
interface CounterState {
count: number
increment: () => void
decrement: () => void
reset: () => void
}
export const useCounterStore = create<CounterState>()(
devtools(
persist(
(set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
decrement: () => set((state) => ({ count: state.count - 1 })),
reset: () => set({ count: 0 }),
}),
{ name: 'counter-storage' }
)
)
)
¿Qué logramos?:
-
persist
guarda el estado enlocalStorage
osessionStorage
. -
devtools
permite inspeccionar el estado con Redux DevTools (sin usar Redux).
Esto facilita el debuggeo y asegura que el contador persista aunque recargues la página.
Si deseas ver un ejemplo más completo, incluyendo un carrito de compras, te invito a leer el siguiente artículo 👇
Zustand: Aprende a gestionar tu estado en React una alternativa sencilla a Redux
Integrando Zod para Validaciones
Aunque Zustand no maneja formularios, en una aplicación real puedes querer validar datos antes de actualizar el estado. Para eso Zod es una excelente opción.
Instalamos:
npm install zod
Ejemplo básico para validar antes de setear:
import { z } from 'zod'
const CountSchema = z.object({
count: z.number().min(0).max(100),
})
export const useCounterStore = create<CounterState>()(
devtools(
persist(
(set) => ({
count: 0,
increment: () => set((state) => {
const result = CountSchema.safeParse({ count: state.count + 1 })
if (result.success) {
return { count: state.count + 1 }
}
console.error(result.error)
return state
}),
decrement: () => set((state) => {
const result = CountSchema.safeParse({ count: state.count - 1 })
if (result.success) {
return { count: state.count - 1 }
}
console.error(result.error)
return state
}),
reset: () => set({ count: 0 }),
}),
{ name: 'counter-storage' }
)
)
)
Conclusión: Con Zod evitamos que el contador pase de ciertos límites definidos de manera declarativa.
Reflexión Final
Zustand representa la evolución natural de la gestión de estado en React: simplicidad, flexibilidad y potencia.
Si estás cansado del exceso de configuración de Redux o simplemente buscas una forma más intuitiva de manejar estados globales, Zustand es, sin duda, una opción que deberías considerar seriamente.
Te invito a visitar mi blog, donde encontrarás más contenido sobre JavaScript, React, CSS, IA, buenas prácticas y mucho más. 👉 johnserrano.co/blog ¡No te lo pierdas!
Gracias por leer. ❤️