0Pricing
Frontend Academy · Lezione

useReducer per stati complessi

Modellare le transizioni di stato con una funzione reducer, inviare oggetti action e preferire useReducer a useState quando la logica dello stato diventa complessa.

useReducer per stati complessi è una lezione Frontend Academy gratuita su CoddyKit. Questa è la lezione 2 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Frontend Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Frontend Academy include 4 lezioni in totale.

Quando useState non basta

Quando le transizioni di stato implicano logica complessa, più valori correlati o condizioni in cui il nuovo stato dipende dallo stato precedente in modi non banali, useReducer è una scelta più pulita rispetto a più chiamate a useState.

Pattern della funzione reducer

Un reducer è una funzione pura: (state, action) => newState. Prende lo stato corrente e un oggetto action, quindi restituisce lo stato successivo. Nessuna mutazione: restituisca sempre un nuovo oggetto.

type Action =
  | { type: 'increment' }
  | { type: 'decrement' }
  | { type: 'reset'; payload: number };

function counterReducer(state: number, action: Action): number {
  switch (action.type) {
    case 'increment': return state + 1;
    case 'decrement': return state - 1;
    case 'reset':     return action.payload;
    default: return state;
  }
}

Sintassi di useReducer

useReducer(reducer, initialState) restituisce lo stato corrente e una funzione dispatch. Chiami dispatch con un oggetto action per attivare una transizione di stato.

function Counter() {
  const [count, dispatch] = useReducer(counterReducer, 0);

  return (
    <div>
      <p>{count}</p>
      <button onClick={() => dispatch({ type: 'increment' })}>+</button>
      <button onClick={() => dispatch({ type: 'decrement' })}>-</button>
      <button onClick={() => dispatch({ type: 'reset', payload: 0 })}>Reset</button>
    </div>
  );
}

Azioni tipizzate — unioni discriminate

Utilizzi i tipi unione discriminati di TypeScript per le azioni, così da ottenere un controllo esaustivo dei tipi nello switch del reducer.

type CartAction =
  | { type: 'ADD_ITEM'; item: CartItem }
  | { type: 'REMOVE_ITEM'; id: string }
  | { type: 'SET_QUANTITY'; id: string; qty: number }
  | { type: 'CLEAR' };

Esempio di stato complesso: carrello della spesa

Un carrello della spesa con operazioni per aggiungere, rimuovere e aggiornare la quantità è un caso d'uso perfetto per useReducer.

interface CartState {
  items: CartItem[];
  total: number;
}

function cartReducer(state: CartState, action: CartAction): CartState {
  switch (action.type) {
    case 'ADD_ITEM': {
      const exists = state.items.find(i => i.id === action.item.id);
      if (exists) {
        const items = state.items.map(i =>
          i.id === action.item.id ? { ...i, qty: i.qty + 1 } : i
        );
        return { ...state, items, total: calcTotal(items) };
      }
      const items = [...state.items, { ...action.item, qty: 1 }];
      return { ...state, items, total: calcTotal(items) };
    }
    case 'CLEAR': return { items: [], total: 0 };
    default: return state;
  }
}

Dispatch è stabile

La funzione dispatch è stabile: non cambia tra un rendering e l'altro. È sicuro passarla come prop o usarla come dipendenza di useEffect senza attivare nuove esecuzioni.

Combinare useReducer e useContext

Un pattern potente: un contesto fornisce sia lo stato sia dispatch, consentendo a qualsiasi consumer di leggere lo stato o inviare azioni senza prop drilling.

const CartContext = createContext<{ state: CartState; dispatch: Dispatch<CartAction> } | null>(null);

function CartProvider({ children }: { children: React.ReactNode }) {
  const [state, dispatch] = useReducer(cartReducer, { items: [], total: 0 });
  return <CartContext.Provider value={{ state, dispatch }}>{children}</CartContext.Provider>;
}

useReducer e useState

Scelga useReducer quando: lo stato ha più sotto-valori, il nuovo stato dipende da quello precedente in modi complessi, le transizioni sono numerose e denominate esplicitamente oppure desidera testare la logica dello stato separatamente dal componente.

Testare i reducer in isolamento

Poiché i reducer sono funzioni pure, è semplicissimo testarli senza eseguire il rendering di alcun componente.

test('increment action increases count', () => {
  expect(counterReducer(0, { type: 'increment' })).toBe(1);
  expect(counterReducer(5, { type: 'increment' })).toBe(6);
});

test('reset action sets count to payload', () => {
  expect(counterReducer(42, { type: 'reset', payload: 0 })).toBe(0);
});

Immer per aggiornamenti immutabili

La libreria immer consente di scrivere codice che sembra mutare lo stato ma produce un nuovo stato immutabile. È utile per aggiornare oggetti annidati complessi nei reducer.

Verifica rapida

Qual è la firma della funzione di un reducer?

Riepilogo: useReducer

(state, action) => newState — puro, nessuna mutazione. useReducer(reducer, initial) restituisce [state, dispatch]. Utilizzi tipi di azione basati su unioni discriminate per maggiore sicurezza. dispatch è stabile. È ideale per stati complessi con molte transizioni. Lo combini con useContext per la gestione dello stato globale. Testi i reducer separatamente come funzioni pure.

Domande Frequenti

La lezione «useReducer per stati complessi» è gratuita?

Sì — il testo completo di «useReducer per stati complessi» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Frontend Academy, passa a CoddyKit PRO. Il corso Frontend Academy include 4 lezioni in totale.

Cosa imparerò in «useReducer per stati complessi»?

Modellare le transizioni di stato con una funzione reducer, inviare oggetti action e preferire useReducer a useState quando la logica dello stato diventa complessa. Eserciti Frontend Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.

Ho bisogno di esperienza per iniziare Frontend Academy?

Non è richiesta alcuna esperienza precedente. Frontend Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 2 di 4.

Quanto tempo richiede la lezione «useReducer per stati complessi»?

La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.

Posso scrivere ed eseguire codice in questa lezione Frontend Academy?

Sì. Ogni lezione Frontend Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.

Tutte le lezioni di questo corso

  1. useContext per lo stato globale
  2. useReducer per stati complessi
  3. useMemo e useCallback per le prestazioni
  4. Custom hook: estrarre logica riutilizzabile
← Torna a Frontend Academy