Store de favoritos con Zustand
En esta clase damos un paso más en la gestión de estado global y creamos una store de favoritos con Zustand. El objetivo es manejar un estado más complejo, con múltiples acciones y lógica reutilizable, sin usar Context, Provider ni dependencias adicionales.
Verás cómo Zustand nos permite definir estado, acciones, estados derivados y helpers de forma clara, optimizada y fácil de testear.
¿Qué vamos a construir?
Una store de favoritos que nos permita:
- Guardar una lista de IDs favoritos.
- Añadir favoritos sin duplicados.
- Eliminar favoritos.
- Saber si un elemento está marcado como favorito.
- Alternar favoritos con una sola acción.
- Calcular estados derivados como el número total de favoritos.
Todo encapsulado en una única store.
Creando la store
Creamos un nuevo archivo para la store:
// favoritesStore.js
import { create } from 'zustand'
export const useFavoritesStore = create((set, get) => ({
favorites: [],
addFavorite: (jobId) =>
set((state) => ({
favorites: state.favorites.includes(jobId) ? state.favorites : [...state.favorites, jobId],
})),
removeFavorite: (jobId) =>
set((state) => ({
favorites: state.favorites.filter((id) => id !== jobId),
})),
isFavorite: (jobId) => {
const { favorites } = get()
return favorites.includes(jobId)
},
toggleFavorite: (jobId) => {
const { isFavorite, addFavorite, removeFavorite } = get()
isFavorite(jobId) ? removeFavorite(jobId) : addFavorite(jobId)
},
favoritesCount: () => get().favorites.length,
}))
Uso de set y get
Zustand nos proporciona dos herramientas clave:
set: actualiza el estado.get: permite leer el estado actual sin provocar renders.
Esto nos permite separar claramente:
- Lógica de actualización.
- Lógica de consulta.
- Reutilización de acciones sin duplicar código.
Evitando duplicados
Al añadir un favorito, comprobamos antes si ya existe:
state.favorites.includes(jobId)
Esto evita estados inconsistentes y comportamientos inesperados en la UI.
Acciones reutilizables
Una de las grandes ventajas es poder reutilizar acciones dentro de la propia store:
toggleFavorite: (jobId) => {
const { isFavorite, addFavorite, removeFavorite } = get()
isFavorite(jobId) ? removeFavorite(jobId) : addFavorite(jobId)
}
Así evitamos repetir lógica y centralizamos el comportamiento en un solo lugar.
Estados derivados
También podemos definir estados derivados sin almacenarlos explícitamente:
favoritesCount: () => get().favorites.length
Esto nos permite calcular información basada en el estado sin duplicar datos ni preocuparnos por sincronización.
Uso en la UI
En cualquier componente React:
const { favorites, toggleFavorite, isFavorite } = useFavoritesStore()
Sin providers, sin wrappers, sin boilerplate adicional.
Ventajas frente a Context
Comparado con una solución basada en Context:
- Menos líneas de código.
- No necesitas Provider.
- Mejor separación de lógica.
- Estado más fácil de testear.
- Actualizaciones más granulares.
Conclusión
Zustand permite crear stores potentes y expresivas con muy poco código. En esta clase has visto cómo manejar un estado realista, con lógica compleja y sin las limitaciones del Context tradicional.