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.

Preguntas de entrevista Zustand 2026

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.

Lo que buscan los entrevistadores

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:

  1. El estado persiste entre montajes y desmontajes de componentes sin providers de Context
  2. Las actualizaciones no disparan re-renderizados en componentes padre, solo se re-renderizan los componentes suscritos
  3. El estado puede accederse síncronamente fuera de React, útil para manejadores de eventos y lógica asíncrona
store.tstypescript
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:

Component.tsxtypescript
// 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.

CriterioContext APIZustand
Tamaño del bundle0 KB (integrado)1.2 KB gzipped
Control de re-rendersManual con memo/useMemoSelectores integrados
DevToolsSolo React DevToolsCompatible con Redux DevTools
Server ComponentsSoporte completoRequiere boundary cliente
Estado asíncronoRequiere wrapperSoporte 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.

Consideración sobre Server Components

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?

store.tstypescript
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:

store.tstypescript
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

store.tstypescript
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:

slices/authSlice.tstypescript
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 })
})
store.tstypescript
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:

store.test.tstypescript
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:

Component.test.tsxtypescript
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:

store.tstypescript
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 de create
  • TypeScript más estricto: El patrón create<T>()() reemplaza a create<T>()
  • Hidratación persist síncrona: El timing del callback onRehydrateStorage cambió
  • 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 partialize para 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.

Reto diario

¿Sabrías detectar el bug en React / Next.js?

Un fragmento real, un bug oculto, un intento al día. Sin cuenta para probar.

Anthony Fillion-Maillet

Escrito por

Anthony Fillion-Maillet

Fundador 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

#zustand
#react
#state-management
#interview
#typescript

Compartir

Artículos relacionados