Domande Colloquio Zustand 2026: Gestione dello State React e Best Practice

Raccolta completa di domande su Zustand per colloqui tecnici React. Pattern degli store, configurazione middleware, integrazione TypeScript e confronto con Context API.

Domande Colloquio Zustand 2026: Gestione dello State React e Best Practice

Zustand si è affermata come la libreria di gestione dello state preferita per le applicazioni React che necessitano di qualcosa in più rispetto alla Context API ma con meno cerimonie rispetto a Redux. Con la sua superficie API minimale e il design TypeScript-first, le domande su Zustand compaiono regolarmente nei colloqui frontend, in particolare per posizioni React di livello mid e senior.

Cosa Cercano gli Intervistatori

Le domande su Zustand testano tre aree: comprensione del pattern store rispetto allo state integrato di React, conoscenza di quando Zustand supera le alternative, e capacità di strutturare gli store per la manutenibilità.

Concetti Fondamentali di Zustand per Ogni Candidato

Zustand v5, rilasciata a fine 2024, ha introdotto diverse breaking change rispetto alla v4. La funzione create non richiede più una chiamata separata a useStore, e il middleware persist utilizza per default un modello di hydration sincrono. Gli intervistatori si aspettano che i candidati conoscano l'API attuale.

Cosa distingue Zustand da useState e useReducer?

Gli store Zustand esistono al di fuori dell'albero dei componenti React. Questa differenza architetturale ha tre conseguenze pratiche:

  1. Lo state persiste attraverso mount e unmount dei componenti senza Context provider
  2. Gli aggiornamenti non causano re-render dei componenti parent, solo i componenti sottoscritti si aggiornano
  3. Lo state può essere accesso in modo sincrono al di fuori di React, utile per event handler e logica asincrona
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 funzione get fornisce accesso sincrono allo state corrente, evitando il problema delle stale closure comune con useState.

Come gestisce Zustand i Re-render?

Zustand utilizza la shallow equality per default. Quando un componente si sottoscrive a uno store con useCartStore(), riceve l'intero oggetto state e si aggiorna ad ogni modifica. Selezionare slice specifici previene render non necessari:

Component.tsxtypescript
// Male: si aggiorna ad ogni cambio dello store
const { items } = useCartStore()

// Bene: si aggiorna solo quando items cambia
const items = useCartStore((state) => state.items)

// Valori multipli: usare shallow comparison
import { shallow } from 'zustand/shallow'

const { items, totalPrice } = useCartStore(
  (state) => ({ items: state.items, totalPrice: state.totalPrice() }),
  shallow
)

Il comparatore shallow da zustand/shallow esegue l'uguaglianza per riferimento sulle proprietà dell'oggetto piuttosto che sull'oggetto stesso.

Zustand vs Context API: Quando Scegliere Ciascuno

Questa domanda di confronto appare in quasi ogni colloquio che tratta la gestione dello state. La risposta dipende dalla frequenza degli aggiornamenti e dalla complessità dello state.

CriterioContext APIZustand
Dimensione bundle0 KB (integrato)1.2 KB gzipped
Controllo re-renderManuale con memo/useMemoSelettori integrati
DevToolsSolo React DevToolsCompatibile con Redux DevTools
Server ComponentsSupporto completoRichiede boundary client
State AsincronoRichiede wrapperSupporto nativo

La Context API funziona bene per valori che cambiano raramente come tema o locale. Zustand eccelle quando gli aggiornamenti dello state sono frequenti, come input di form, dati real-time o carrelli. La documentazione React sulla gestione dello state raccomanda di sollevare lo state e usare Context per problemi di "prop drilling", mentre gli store esterni sono adatti per pattern di aggiornamento complessi.

Considerazione sui Server Components

Gli store Zustand richiedono la direttiva "use client". Per applicazioni che usano intensivamente React Server Components, questo significa che lo state Zustand vive solo nei componenti client. Le architetture ibride spesso passano dati recuperati dal server come props ai componenti client che poi si sincronizzano con Zustand.

Pattern Middleware in Zustand

Le domande sui middleware testano se un candidato comprende la composizione rispetto alla configurazione. Il middleware Zustand avvolge la funzione store creator, aggiungendo comportamenti senza modificare l'API core.

Come funziona il 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 })
    }
  )
)

L'opzione partialize esclude funzioni e state derivato dalla persistenza. Senza di essa, la serializzazione fallisce o lo storage si gonfia con dati non necessari. La documentazione Zustand su persist copre le strategie di migrazione per i cambiamenti di schema.

Combinare più middleware

I middleware si compongono dall'interno verso l'esterno. Il middleware più interno viene eseguito per primo:

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 e actions
        }))
      ),
      { name: 'app-storage' }
    ),
    { name: 'AppStore' }
  )
)

Il middleware immer abilita aggiornamenti in stile mutabile che producono state immutabile. Il middleware subscribeWithSelector permette di sottoscriversi a slice dello state al di fuori dei componenti React.

Pronto a superare i tuoi colloqui su React / Next.js?

Pratica con i nostri simulatori interattivi, flashcards e test tecnici.

Pattern di Integrazione TypeScript

Zustand v5 ha migliorato significativamente l'inferenza TypeScript. Il pattern della doppia chiamata di funzione create<Type>()() fornisce inferenza di tipo completa per le catene di middleware.

Tipizzare actions che referenziano altro state

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
    }
  }
}))

Lo state derivato come funzioni invece che getter evita valori obsoleti. Ogni chiamata a filteredTodos() legge lo state corrente.

Dividere gli store per applicazioni grandi

Una domanda comune nei colloqui chiede come strutturare Zustand per la scalabilità. Il pattern slice divide uno store in moduli di 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 store combinato
  [],
  [],
  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)
}))

Gli slice possono referenziarsi a vicenda attraverso il tipo store combinato passato a StateCreator.

Domande Comuni nei Colloqui con Risposte Modello

Quando Zustand sarebbe una scelta sbagliata?

Zustand aggiunge complessità senza benefici in questi scenari:

  • Dati di configurazione statici che non cambiano mai a runtime
  • State dei form gestito da React Hook Form o librerie simili
  • State del server gestito meglio da TanStack Query o SWR
  • Passaggio di props parent-child semplice con 2-3 livelli di nesting

La sezione confronto nel repository GitHub di Zustand fornisce la prospettiva dei maintainer sulle alternative.

Come si testano i componenti che usano Zustand?

Il testing richiede il reset dello state dello store tra i test e opzionalmente il mock completo dello store:

store.test.tstypescript
import { act, renderHook } from '@testing-library/react'
import { useCartStore } from './store'

beforeEach(() => {
  // Reset dello store allo state iniziale
  useCartStore.setState({ items: [], totalItems: 0 })
})

test('addItem incrementa il conteggio del carrello', () => {
  const { result } = renderHook(() => useCartStore())
  
  act(() => {
    result.current.addItem({ id: '1', name: 'Product', price: 10 })
  })
  
  expect(result.current.items).toHaveLength(1)
})

Per i test dei componenti che non devono interagire con store reali, mockare a livello di modulo:

Component.test.tsxtypescript
import { vi } from 'vitest'

vi.mock('./store', () => ({
  useCartStore: vi.fn(() => ({
    items: [{ id: '1', name: 'Mock Product', price: 25 }],
    addItem: vi.fn()
  }))
}))

Come gestisce Zustand le operazioni asincrone?

A differenza di Redux, Zustand non richiede middleware per l'async. Le actions possono essere direttamente funzioni async:

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 })
    }
  }
}))

Per flussi asincroni complessi, la guida Zustand sui pattern async raccomanda di mantenere gli state di loading e error collocati con i dati che descrivono.

Cambiamenti in Zustand v5 che Potrebbero Apparire nei Colloqui

Zustand v5 ha introdotto breaking change che gli intervistatori usano per valutare se i candidati sono aggiornati:

  • Niente più export default: Importare { create } invece di create
  • TypeScript più rigoroso: Il pattern create<T>()() sostituisce create<T>()
  • Hydration persist sincrona: Il timing del callback onRehydrateStorage è cambiato
  • Rimosso supporto CJS: Pacchetto solo ESM

Migrare da v4 a v5 richiede l'aggiornamento delle dichiarazioni di import e l'adattamento del codice che si basava sul vecchio timing di hydration.

Punti Chiave per i Colloqui su Zustand

  • Gli store Zustand vivono al di fuori dell'albero React, abilitando l'accesso sincrono e prevenendo il nesting dei provider
  • I selettori con shallow comparison ottimizzano i re-render per le applicazioni in produzione
  • Il middleware persist richiede partialize per escludere le funzioni dallo storage
  • Il pattern slice scala Zustand per applicazioni grandi senza sacrificare la type safety
  • Le actions async funzionano direttamente senza middleware, a differenza dei pattern Redux
  • Il testing richiede reset esplicito dello state tra i test case
  • I Server Components forzano Zustand ai boundary client, influenzando le decisioni architetturali

Inizia a praticare!

Metti alla prova le tue conoscenze con i nostri simulatori di colloquio e test tecnici.

Sfida del giorno

Sapresti trovare il bug in React / Next.js?

Uno snippet reale, un bug nascosto, un tentativo al giorno. Senza account per provare.

Anthony Fillion-Maillet

Scritto da

Anthony Fillion-Maillet

Fondatore di SharpSkill

Sviluppatore fullstack da oltre 10 anni. Guida SharpSkill e risponde di tutto ciò che vi viene pubblicato.

Aggiornato il 25 agosto 2026

Condividi

Articoli correlati