Preguntas de entrevista sobre Zustand 2026: Gestión de estado en React y mejores prácticas
Prepara tus entrevistas técnicas con esta guía completa sobre Zustand. Descubre las preguntas frecuentes, patrones de middleware, comparación con Context API y mejores prácticas de TypeScript.

Zustand se ha convertido en la biblioteca de gestión de estado preferida para aplicaciones React que necesitan más que la Context API pero menos ceremonial que Redux. Con su API minimalista y diseño TypeScript-first, las preguntas sobre Zustand aparecen regularmente en entrevistas frontend, particularmente para posiciones React de nivel medio y senior.
Las preguntas de entrevista sobre Zustand evalúan tres áreas: comprensión del patrón store versus el estado nativo de React, conocimiento de cuándo Zustand supera a las alternativas, y capacidad para estructurar stores mantenibles.
Conceptos fundamentales de Zustand que todo candidato debe conocer
Zustand v5, lanzado a finales de 2024, introdujo varios cambios importantes respecto a la v4. La función create ya no requiere una llamada separada a useStore, y el middleware persist ahora usa un modelo de hidratación síncrona por defecto. Los entrevistadores esperan que los candidatos conozcan la API actual.
¿Qué hace diferente a Zustand de useState y useReducer?
Los stores de Zustand existen fuera del árbol de componentes React. Esta diferencia arquitectónica tiene tres consecuencias prácticas:
- El estado persiste entre montajes y desmontajes de componentes sin providers de Context
- Las actualizaciones no disparan re-renderizados en componentes padre, solo se re-renderizan los componentes suscritos
- El estado puede accederse síncronamente fuera de React, útil para manejadores de eventos y lógica asíncrona
import { create } from 'zustand'
interface CartStore {
items: CartItem[]
addItem: (item: CartItem) => void
clearCart: () => void
totalPrice: () => number
}
export const useCartStore = create<CartStore>((set, get) => ({
items: [],
addItem: (item) => set((state) => ({
items: [...state.items, item]
})),
clearCart: () => set({ items: [] }),
totalPrice: () => get().items.reduce((sum, item) => sum + item.price, 0)
}))La función get proporciona acceso síncrono al estado actual, evitando el problema de closure obsoleto común con useState.
¿Cómo maneja Zustand los re-renderizados?
Zustand usa igualdad superficial por defecto. Cuando un componente se suscribe a un store con useCartStore(), recibe el objeto de estado completo y se re-renderiza con cualquier cambio. Seleccionar slices específicos previene renderizados innecesarios:
// Malo: se re-renderiza con cualquier cambio en el store
const { items } = useCartStore()
// Bueno: se re-renderiza solo cuando items cambia
const items = useCartStore((state) => state.items)
// Múltiples valores: usar comparación superficial
import { shallow } from 'zustand/shallow'
const { items, totalPrice } = useCartStore(
(state) => ({ items: state.items, totalPrice: state.totalPrice() }),
shallow
)El comparador shallow de zustand/shallow realiza igualdad de referencia en las propiedades del objeto en lugar del objeto mismo.
Zustand vs Context API: cuándo elegir cada uno
Esta pregunta de comparación aparece en casi todas las entrevistas que cubren gestión de estado. La respuesta depende de la frecuencia de actualizaciones y la complejidad del estado.
| Criterio | Context API | Zustand |
|---|---|---|
| Tamaño del bundle | 0 KB (integrado) | 1.2 KB gzipped |
| Control de re-renders | Manual con memo/useMemo | Selectores integrados |
| DevTools | Solo React DevTools | Compatible con Redux DevTools |
| Server Components | Soporte completo | Requiere boundary cliente |
| Estado asíncrono | Requiere wrapper | Soporte nativo |
La Context API funciona bien para valores que cambian poco frecuentemente como el tema o el locale. Zustand destaca cuando las actualizaciones de estado ocurren frecuentemente, como inputs de formulario, datos en tiempo real o carritos de compra. La documentación de React sobre gestión de estado recomienda elevar el estado y usar Context para problemas de "prop drilling", mientras que los stores externos son adecuados para patrones de actualización complejos.
Los stores de Zustand requieren la directiva "use client". Para aplicaciones que usan React Server Components extensivamente, esto significa que el estado de Zustand vive solo en componentes cliente. Las arquitecturas híbridas frecuentemente pasan datos obtenidos del servidor como props a componentes cliente que luego se sincronizan con Zustand.
Patrones de middleware en Zustand
Las preguntas sobre middleware evalúan si un candidato entiende la composición sobre la configuración. Los middleware de Zustand envuelven la función creadora del store, agregando comportamiento sin modificar la API principal.
¿Cómo funciona el middleware persist?
import { create } from 'zustand'
import { persist, createJSONStorage } from 'zustand/middleware'
interface UserPreferences {
theme: 'light' | 'dark'
language: string
setTheme: (theme: 'light' | 'dark') => void
}
export const usePreferencesStore = create<UserPreferences>()(
persist(
(set) => ({
theme: 'light',
language: 'en',
setTheme: (theme) => set({ theme })
}),
{
name: 'user-preferences',
storage: createJSONStorage(() => localStorage),
partialize: (state) => ({ theme: state.theme, language: state.language })
}
)
)La opción partialize excluye funciones y estado derivado de la persistencia. Sin ella, la serialización falla o el almacenamiento se infla con datos innecesarios. La documentación de Zustand sobre persist cubre estrategias de migración para cambios de esquema.
Combinar múltiples middleware
Los middleware se componen de adentro hacia afuera. El middleware más interno se ejecuta primero:
import { create } from 'zustand'
import { devtools, persist, subscribeWithSelector } from 'zustand/middleware'
import { immer } from 'zustand/middleware/immer'
export const useStore = create<StoreState>()(
devtools(
persist(
subscribeWithSelector(
immer((set) => ({
// state and actions
}))
),
{ name: 'app-storage' }
),
{ name: 'AppStore' }
)
)El middleware immer permite actualizaciones de estilo mutable que producen estado inmutable. El middleware subscribeWithSelector permite suscribirse a slices de estado fuera de los componentes React.
¿Listo para aprobar tus entrevistas de React / Next.js?
Practica con nuestros simuladores interactivos, flashcards y tests técnicos.
Patrones de integración con TypeScript
Zustand v5 mejoró significativamente la inferencia de TypeScript. El patrón de doble llamada de función create<Type>()() proporciona inferencia de tipos completa para cadenas de middleware.
Tipar acciones que referencian otro estado
interface TodoStore {
todos: Todo[]
filter: 'all' | 'active' | 'completed'
addTodo: (text: string) => void
toggleTodo: (id: string) => void
filteredTodos: () => Todo[]
}
export const useTodoStore = create<TodoStore>()((set, get) => ({
todos: [],
filter: 'all',
addTodo: (text) => set((state) => ({
todos: [...state.todos, { id: crypto.randomUUID(), text, completed: false }]
})),
toggleTodo: (id) => set((state) => ({
todos: state.todos.map((todo) =>
todo.id === id ? { ...todo, completed: !todo.completed } : todo
)
})),
filteredTodos: () => {
const { todos, filter } = get()
switch (filter) {
case 'active': return todos.filter((t) => !t.completed)
case 'completed': return todos.filter((t) => t.completed)
default: return todos
}
}
}))El estado derivado como funciones en lugar de getters evita valores obsoletos. Cada llamada a filteredTodos() lee el estado actual.
Dividir stores para aplicaciones grandes
Una pregunta de entrevista común pregunta cómo estructurar Zustand para escalar. El patrón slice divide un store en módulos por dominio:
import { StateCreator } from 'zustand'
export interface AuthSlice {
user: User | null
isAuthenticated: boolean
login: (credentials: Credentials) => Promise<void>
logout: () => void
}
export const createAuthSlice: StateCreator<
AuthSlice & CartSlice, // Tipo del store combinado
[],
[],
AuthSlice
> = (set) => ({
user: null,
isAuthenticated: false,
login: async (credentials) => {
const user = await authApi.login(credentials)
set({ user, isAuthenticated: true })
},
logout: () => set({ user: null, isAuthenticated: false })
})import { create } from 'zustand'
import { createAuthSlice, AuthSlice } from './slices/authSlice'
import { createCartSlice, CartSlice } from './slices/cartSlice'
export const useStore = create<AuthSlice & CartSlice>()((...args) => ({
...createAuthSlice(...args),
...createCartSlice(...args)
}))Los slices pueden referenciarse entre sí a través del tipo de store combinado pasado a StateCreator.
Preguntas de entrevista comunes con respuestas modelo
¿Cuándo sería Zustand una mala elección?
Zustand agrega complejidad sin beneficio en estos escenarios:
- Datos de configuración estática que nunca cambian en tiempo de ejecución
- Estado de formulario manejado por React Hook Form o bibliotecas similares
- Estado del servidor mejor manejado por TanStack Query o SWR
- Paso de props simple padre-hijo con 2-3 niveles de anidamiento
La sección de comparación del repositorio GitHub de Zustand proporciona la perspectiva de los mantenedores sobre las alternativas.
¿Cómo probar componentes que usan Zustand?
Las pruebas requieren reiniciar el estado del store entre tests y opcionalmente mockear el store completamente:
import { act, renderHook } from '@testing-library/react'
import { useCartStore } from './store'
beforeEach(() => {
// Reiniciar el store al estado inicial
useCartStore.setState({ items: [], totalItems: 0 })
})
test('addItem increases cart count', () => {
const { result } = renderHook(() => useCartStore())
act(() => {
result.current.addItem({ id: '1', name: 'Product', price: 10 })
})
expect(result.current.items).toHaveLength(1)
})Para pruebas de componentes que no deben interactuar con stores reales, mockear a nivel de módulo:
import { vi } from 'vitest'
vi.mock('./store', () => ({
useCartStore: vi.fn(() => ({
items: [{ id: '1', name: 'Mock Product', price: 25 }],
addItem: vi.fn()
}))
}))¿Cómo maneja Zustand las operaciones asíncronas?
A diferencia de Redux, Zustand no tiene requerimiento de middleware para async. Las acciones pueden ser funciones asíncronas directamente:
interface ProductStore {
products: Product[]
isLoading: boolean
error: string | null
fetchProducts: () => Promise<void>
}
export const useProductStore = create<ProductStore>((set) => ({
products: [],
isLoading: false,
error: null,
fetchProducts: async () => {
set({ isLoading: true, error: null })
try {
const products = await productApi.getAll()
set({ products, isLoading: false })
} catch (err) {
set({ error: err.message, isLoading: false })
}
}
}))Para flujos asíncronos complejos, la guía de patrones async de Zustand recomienda mantener los estados de carga y error colocalizados con los datos que describen.
Cambios de Zustand v5 que pueden aparecer en entrevistas
Zustand v5 introdujo cambios importantes que los entrevistadores usan para evaluar si los candidatos se mantienen actualizados:
- Sin más exports por defecto: Importar
{ create }en lugar decreate - TypeScript más estricto: El patrón
create<T>()()reemplaza acreate<T>() - Hidratación persist síncrona: El timing del callback
onRehydrateStoragecambió - Abandono del soporte CJS: Paquete solo ESM
Migrar de v4 a v5 requiere actualizar las declaraciones de importación y ajustar cualquier código que dependía del timing de hidratación anterior.
Puntos clave para entrevistas sobre Zustand
- Los stores de Zustand viven fuera del árbol React, permitiendo acceso síncrono y previniendo anidamiento de providers
- Los selectores con comparación superficial optimizan los re-renders para aplicaciones en producción
- El middleware persist requiere
partializepara excluir funciones del almacenamiento - El patrón slice escala Zustand a aplicaciones grandes sin sacrificar la seguridad de tipos
- Las acciones async funcionan directamente sin middleware, a diferencia de los patrones Redux
- Las pruebas requieren reinicio explícito del estado entre casos de prueba
- Los Server Components fuerzan a Zustand a los boundaries cliente, influenciando decisiones de arquitectura
¡Empieza a practicar!
Pon a prueba tu conocimiento con nuestros simuladores de entrevista y tests técnicos.
¿Sabrías detectar el bug en React / Next.js?
Un fragmento real, un bug oculto, un intento al día. Sin cuenta para probar.

Escrito por
Anthony Fillion-MailletFundador de SharpSkill
Desarrollador fullstack desde hace más de 10 años. Dirige SharpSkill y responde por todo lo que se publica aquí.
Actualizado el 25 de agosto de 2026
Etiquetas
Compartir
Artículos relacionados

React 19 Suspense y Renderizado Concurrente: Streaming SSR y Preguntas de Entrevista 2026
Guía completa sobre React 19 Suspense, renderizado concurrente y Streaming SSR. Patrones avanzados y preparación para entrevistas técnicas en 2026.

React Compiler en 2026: memoización automática y preguntas de entrevista
Análisis completo del React Compiler en 2026: pipeline de compilación, memoización automática, reglas de React y preguntas frecuentes en entrevistas técnicas.

Server Actions de Next.js 16 en 2026: mutaciones, revalidación y preguntas de entrevista
Cómo las Server Actions de Next.js 16 manejan mutaciones, revalidación, estado pendiente, UI optimista y seguridad, con las preguntas de entrevista que evalúan cada concepto.