00
:
00
:
00
:
00
Corso SEO AI - Usa SEOEMAIL al checkout per il 30% di sconto

Middleware Immer

Perché Immer

Aggiornare stato annidato in modo immutabile richiede spread operator a ogni livello. Con oggetti complessi il codice diventa illeggibile. Immer ti permette di scrivere aggiornamenti “mutabili” che vengono convertiti automaticamente in aggiornamenti immutabili.

Installazione

npm install immer

Il middleware immer e’ incluso in Zustand, non serve installare pacchetti aggiuntivi oltre a immer stesso.

Configurazione

import { create } from 'zustand'
import { immer } from 'zustand/middleware/immer'

interface TodoState {
  todos: { id: string; text: string; done: boolean }[]
  addTodo: (text: string) => void
  toggleTodo: (id: string) => void
}

const useTodoStore = create<TodoState>()(
  immer((set) => ({
    todos: [],

    addTodo: (text) =>
      set((state) => {
        state.todos.push({ id: crypto.randomUUID(), text, done: false })
      }),

    toggleTodo: (id) =>
      set((state) => {
        const todo = state.todos.find((t) => t.id === id)
        if (todo) todo.done = !todo.done
      }),
  }))
)

Nota come push e l’assegnazione diretta sostituiscono spread e map. Immer intercetta le mutazioni e produce un nuovo oggetto immutabile.

Aggiornamenti Nested

Immer brilla con stato profondamente annidato.

interface SettingsState {
  config: {
    theme: {
      primary: string
      secondary: string
      fonts: { heading: string; body: string }
    }
    notifications: { email: boolean; push: boolean }
  }
  updateHeadingFont: (font: string) => void
  toggleEmailNotification: () => void
}

const useSettingsStore = create<SettingsState>()(
  immer((set) => ({
    config: {
      theme: {
        primary: '#3b82f6',
        secondary: '#10b981',
        fonts: { heading: 'Inter', body: 'Roboto' },
      },
      notifications: { email: true, push: false },
    },

    updateHeadingFont: (font) =>
      set((state) => {
        state.config.theme.fonts.heading = font
      }),

    toggleEmailNotification: () =>
      set((state) => {
        state.config.notifications.email = !state.config.notifications.email
      }),
  }))
)

Senza immer, updateHeadingFont richiederebbe tre livelli di spread.

Combinare Immer con Altri Middleware

I middleware Zustand si compongono avvolgendo uno dentro l’altro. Immer deve essere il piu’ interno (il piu’ vicino alla funzione di creazione dello store).

import { create } from 'zustand'
import { devtools, persist } from 'zustand/middleware'
import { immer } from 'zustand/middleware/immer'

const useStore = create<MyState>()(
  devtools(
    persist(
      immer((set) => ({
        // stato e azioni con sintassi mutabile
        count: 0,
        increment: () => set((state) => { state.count++ }),
      })),
      { name: 'my-storage' }
    )
  )
)

L’ordine di composizione dall’esterno all’interno e’: devtools > persist > immer.

Quando Usare Immer

Scenario Immer?
Stato piatto (pochi campi primitivi) No, spread e’ sufficiente
Stato annidato a 2+ livelli Si, semplifica molto
Array di oggetti con aggiornamenti frequenti Si, push/splice sono piu’ leggibili
Store molto semplice No, aggiunge una dipendenza inutile
Team abituato a Redux Toolkit Si, stessa esperienza di scrittura

Immer aggiunge circa 6KB (gzipped) al bundle. Per store semplici con stato piatto, lo spread nativo e’ preferibile. Per stato complesso e annidato, immer migliora significativamente la leggibilita’ e riduce il rischio di errori.