Redux - fromScarso2King - 6 - I Reducer

La vera storia dei reducer dai tempi dello switch.

Andrea Simone Porceddu
VLK Studio
4 min readJan 4, 2021

--

Di cosa parliamo in questo articolo?

Ci siamo, siamo arrivati al punto in cui finalmente, dopo aver cliccato su quel bottone e dispatchato la nostra action sta per esserci restituito un nuovissimo stato. Mancano gli ultimi 20 metri, il reducer, appunto.

In questo articolo parleremo di come funziona questo pezzetto di stato, come si creava, e come si crea ora. Vedremo inoltre i metodi forniti da Redux toolkit per la creazione.

Cosa è un reducer?

Il reducer è una funzione, che prende in input due parametri: il primo è lo stato e il secondo è una action; viene lanciato dal dispatcher, e restituisce un nuovo stato in base al tipo e al payload della action ricevuta.

La sintassi che vedete in questo snippet, è stata uno standard per lungo tempo. I reducer sono stati tipicamente sviluppati come switch, ma esistono dei metodi più moderni che permettono di svilupparli con sintassi più pulite.

Come Scrivere un reducer 2.0

Come anticipato, esistono modi molto più puliti di sviluppare un reducer. Il problema dello switch, è che in reducer che gestiscono molti casi, la funzione può diventare molto sporca, ma non solo, quando i casi si moltiplicano lo switch diventa anche meno performante.

Old dirty reducer

Prendete come esempio lampante questo, ci ritroviamo uno switch enorme, che potenzialmente potrebbe crescere ancora creando non pochi problemi di mantenibilità. Date un occhiata qui:

Soluzione Metodo funzione + mappa

Per lungo tempo abbiamo ovviato al problema sviluppando i case come funzioni separate e trasformando il reducer in una funzione che fa riferimento a una mappa:

Molto meglio no? 29 vs 76 righe di codice, casi più isolati, leggibilità perfetta.

Benché questo metodo sia molto pulito e leggibile, Redux toolkit fornisce un metodo specifico per la creazione di reducer. Al fine di integrarci al meglio con la soluzione preferiamo usare questo.

createReducer

Il metodo createReducer di Redux toolkit è una funzione che prende in input due parametri:

  • Il primo è lo stato iniziale, che rappresenta il valore del nostro stato allo start.
  • Il secondo parametro è una callback, detta builderCallback. Si tratta di una funzione che passa come argomento il builder, ovvero l’oggetto che ci permetterà di aggiungere casi al nostro reducer attraverso dei metodi chainable: addCase, addMatcher, addDefaultCase.

L’ addMatcher, può lanciare un determinato case nel momento in cui una determinata condizione verificata tramite apposita funzione venga verificata.

Ecco un esempio concreto, dove ovviamente come nel metodo precedente, preferiamo scrivere i nostri casi in file separati per mantenere il file più pulito e leggibile:

Qui anche un esempio di come di solito organizziamo un file con i case:

Come potete vedere, in base alla folder structure che vi abbiamo spiegato in una delle puntate precedenti, il file contiene solo i casi per l’action di creazione, si chiamerà appunto create.ts mentre il reducer principale viene sviluppato sul file rootReducer.ts. Questo permetterà al file di non crescere mai, e questo a lungo andare, fidati, ti salverà la vita.

Come unire i reducer di domini dati diversi

Come anticipato nelle prime puntate di questa serie, lo stato applicativo nella sua totalità può considerarsi l’insieme di stati diversi.

Nel nostro caso potremo aver diviso i nostri stati per domini funzionali e ancora per domini dati, quindi ci ritroveremo durante lo sviluppo di un’applicazione a dover riportare diversi livelli su un solo reducer finale che sarà anche quello passato alla funzione configureStore .

Fortunatamente Redux toolkit(ma in generale Redux) ci forniscono un metodo apposito per il merge di diversi reducer: combineReducer.

Il metodo è ultra-semplice da implementare. Si tratta di una funzione che prende in input un oggetto con chiave uguale al nome di quel pezzetto di stato(solitamente il dominio funzionale o dati) e come valore il rootReducer relativo.

Tips and Tricks

  • Tieni i casi su file separati per lasciare il reducer più pulito
  • Non mettere mai logica nei reducer, lascia pulito il più possibile il case, o al massimo esternalizza qualche semplice funzionalità logica creando delle utility.
  • Esistono dei tools per garantire l’ immutabilità dello stato(ad esempio immer). Consideriamo questo tipo di tools in un certo senso diseducativi, in quanto spingono a una scrittura formalmente errata. Per esempio consentono di usare la dot notation per cambiare lo stato sui reducer es. state.data = action.payload. Pensando alle giovani leve che arrivano su un progetto, desiderose di imparare, questo ci sembra tremendamente sbagliato: potrebbero pensare si tratti della prassi/potrebbero sbattersene per sempre di imparare a scrivere in modo immutabile.
  • Gestisci gli stati di loading in modo che sia il più preciso possibile per dare dei feedback precisi alla UI. Non limitarti a loading ma fai sapere all’utente quale tipo di operazione lato server stiamo compiendo es. creating deleting ecc.
  • Mantieni il formato dei reducer coerente ed omogeneo per tutti i domini funzionali/dati

Continua la serie

Anche il capitolo reducer può dirsi chiuso. Ci mancano ancora due piccoli pezzetti per completare il nostro viaggio all’interno dello stato.

  • Come e dove gestiamo le action asincrone? (saga)
  • Come portiamo i dati del nostro reducer sulla UI? (selector)

Nel prossimo articolo vedremo i selector. Leggilo subito qui!

Qui sotto trovi i link alle altre puntate di questa serie

Fuori serie: 0. Le basi

  1. Il Data Flow
  2. Librerie
  3. Folder Structure
  4. Lo Store
  5. Le Action
  6. I Reducer 👈 tu sei qui!
  7. I Selector
  8. I Middleware
  9. Le Saga
  10. Mini App

--

--