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.

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.
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:
- Lo state persiste attraverso mount e unmount dei componenti senza Context provider
- Gli aggiornamenti non causano re-render dei componenti parent, solo i componenti sottoscritti si aggiornano
- Lo state può essere accesso in modo sincrono al di fuori di React, utile per event handler e logica asincrona
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:
// 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.
| Criterio | Context API | Zustand |
|---|---|---|
| Dimensione bundle | 0 KB (integrato) | 1.2 KB gzipped |
| Controllo re-render | Manuale con memo/useMemo | Selettori integrati |
| DevTools | Solo React DevTools | Compatibile con Redux DevTools |
| Server Components | Supporto completo | Richiede boundary client |
| State Asincrono | Richiede wrapper | Supporto 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.
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?
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:
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
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:
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 })
})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:
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:
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:
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 dicreate - TypeScript più rigoroso: Il pattern
create<T>()()sostituiscecreate<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
partializeper 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.
Sapresti trovare il bug in React / Next.js?
Uno snippet reale, un bug nascosto, un tentativo al giorno. Senza account per provare.

Scritto da
Anthony Fillion-MailletFondatore 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

Next.js 16 Middleware nel 2026: Edge Runtime, Autenticazione e Domande da Colloquio
Guida completa a Next.js 16 Middleware con Edge Runtime, pattern di autenticazione, URL rewriting e domande tecniche frequenti nei colloqui per sviluppatori frontend.

React 19 Suspense e Concurrent Rendering: Streaming SSR e Domande di Colloquio 2026
Guida completa a React 19 Suspense, Concurrent Rendering e Streaming SSR. Include esempi di codice pratici e le domande più frequenti nei colloqui tecnici del 2026.

React Testing nel 2026: Vitest, React Testing Library e Best Practice
Strategie professionali per il testing di React nel 2026 con Vitest come test runner e React Testing Library per test dei componenti basati sul comportamento.