Redux - fromScarso2King - 4 - Lo Store

Lo store di Redux a nud(dle)o

Mauro Erta
VLK Studio
5 min readJan 4, 2021

--

Nella puntata precedente abbiamo parlato della Folder Structure e vi abbiamo presentato la nostra proposta ultra-scalabile. Se te la sei persa, la puoi leggere qui.

Ora finalmente andiamo a toccare con mano mister Redux! La puntata di oggi si focalizza sullo store, uno degli elementi principali dell’architettura Redux.

Cos’è lo Store? e cosa vuole da me?

Lo store è un oggetto che ci permette di gestire il nostro stato applicativo fornendoci dei metodi che possiamo utilizzare per leggerlo e modificarlo.

Nello specifico espone i seguenti metodi:

  1. dispatch: la funzione per emettere le action allo store al fine di aggiornare lo stato
  2. getState: una funzione che quando richiamata restituisce lo stato applicativo
  3. subscribe: permette di registrare una funzione (listener) che verrà richiamata quando lo stato cambia.
  4. replaceReducer: utile in ottimizzazioni molto avanzate, per implementare hot reloading e code splitting. Ci interessa il giusto 😒

Tipicamente però non andremo ad utilizzare direttamente l’oggetto store, esso infatti verrà passato ad un Provider che ci permetterà di utilizzare questi metodi ovunque all’interno della nostra app.

Definire lo stato

Prima di passare all’implementazione della creazione dello stato, è giusto fermarci un attimo e pensare come dovrebbe essere, quali sono i dati che dovrà gestire e come interagirà con l’applicazione.

Come ribadito nelle scorse puntate, nel pattern di Redux lo store è univoco; Ma questo non ci impedisce di “pensarlo” come una combinazione di diversi stati. Seguendo quando detto sulla folder structure della scorsa puntata possiamo immaginare il nostro stato come l’unione degli stati definiti in ognuno dei suoi domini.

Daremo quindi ora una struttura generica che si applica molto bene ad una grande varietà di circostanze.

Modello Generico

In questo modello vediamo 3 parametri:

  1. data: è il dato da immagazzinare nello stato;
  2. rollbackData: è dello stesso tipo di data, è opzionale, e serve nel momento in cui si eseguono operazioni di creazione/modifica/rimozione per conservare il valore precedente in caso sia necessario un ripristino;
  3. status: Che definisce lo stato dello stato… okay suona malissimo, diciamo che indica la consistenza dei nostri dati nello stato, sto caricando degli elementi? sto modificando quelli attuali? status indicherà puntualmente queste condizioni.

Questo modello è declinabile in tantissime circostanze, nella mini app lo vedremo infatti usato per gestire dati eterogenei, ma nello specifico vorrei proporre 3 casi d’uso: sincrono, asincrono, lista.

Modello sincrono

Questo modello può essere utilizzato in tutte quelle circostanze in cui i dati non vengono reperiti da servizi esterni, sono custoditi nello store per essere accessibili da tutte le parti dell’app ma sono dati locali, un esempio potrebbero essere le traduzioni della nostra App:

è ovviamente una semplificazione, le traduzioni sono un argomento croccante e tipicamente vengono gestite con librerie esterne, a noi piace tanto i18next

In questo caso i dati sono statici, non abbiamo bisogno del rollback e nemmeno dello status.

Modello Asincrono

In questo caso invece avremo bisogno di tutti e 3 gli attributi, un esempio potrebbe essere la porzione di stato che si occupa della gestione dei dati dell’utente:

In questo caso si intravede l’utilità di questi due attributi, se ad esempio tramite un form modifico il nome dell’utente posso:

  1. Effettuare la richiesta al server di modifica dell’utente
  2. Cominciare a modificare la stato mettendo su data la modifica proposta, ma salvare la vecchia configurazione su rollbackData;
  3. Mettere lo status in updating così che, eventualmente, posso mostrare a UI l’operazione di modifica dell’utente;
  4. Nel momento in cui ricevo risposta positiva dal server riporto lo status su idle.
  5. Se invece ricevo esito negativo dal server, ripristino l’attributo data attraverso rollbackData.

Questa gestione vi ricorda qualcosa?

Modello Asincrono + Gestione Lista

Molto spesso ci capita di gestire delle liste, come ad esempio una lista di articoli in un blog oppure una todo list. In tal caso possiamo scalare il modello e pensarlo a 2 livelli, in quanto le operazioni di creazione, lettura, rimozione e modifica (CRUD) può essere effettuata sull’intera lista ma anche puntualmente sul singolo elemento.

La gestione delle liste è sicuramente la più delicata, qui sotto faremo l’esempio di una lista di articoli:

Il modello che si viene a creare quindi è il seguente:

Sembra complicato ma in realtà e facile capire il motivo di questa struttura:

  1. Se modifico un articolo singolarmente posso aggiornare puntualmente il suo stato, e quindi modificare la UI consistentemente mettendo un loader o uno skeleton nel caso di fetching o utilizzando in maniera precisa il rollback nel caso di modifica/rimozione;
  2. Mantengo la possibilità di avere informazioni sullo stato globale della lista, posso quindi effettuare azioni massive come modifica/rimozione di più elementi o caricamento di più articoli contemporaneamente.

Avrete notato anche gli articoli sono stati raggruppati in 2 attributi:

  1. allIds: che è un array con tutti gli id degli articoli
  2. byId: dove invece troviamo tutti gli articoli per intero, ma raggruppati in un oggetto che ha come chiave l’id dell’articolo.

Questa gestione permette di riferisci tramite id direttamente all’elemento voluto (banalmente articles.data.byId[id].data) ma anche di preservare l’ordinamento con cui li abbiamo ricevuti o come li vogliamo presentare tramite l’array allIds.

Questa forma, per dovere di cronaca, non l’abbiamo inventata noi, anzi, è suggerita nella documentazione ufficiale di Redux

Molto spesso capita di non dover gestire liste enormi o di non avere la necessità di gestire gli stati interni dei singoli elementi della lista. In tal caso non “over ingegnerizziamo” e buttiamo direttamente l’array nel modello generico (KISS — KEEP IT SIMPLE, STUPID!).

One more thing

Piccola e doverosa precisazione sull’attributo status. In moltissimi progetti abbiamo optato per una gestione differente, spezzando status in vari attributi come isLoading, isLoaded, isUpdating etc… attualmente stiamo optando per questa soluzione (più precisamente usando un enumerativo), ho visto però utilizzare anche altri modelli come ad esempio vere e proprie macchine di stato.

Altre soluzioni invece, che abbiamo sperimentato e troviamo altrettanto valide, prevedono una centralizzazione degli stati di loading e della gestione degli errori.

Su questo argomento ci sarebbe da scrivere un altro articolo, che magari faremo, per questa serie però abbiamo scelto questo modello ma ci tenevamo a specificare che a seconda delle circostanze è giusto prendere scelte differenti.

Creazione di uno store

Una volta che ci è chiaro come sarà modellato il nostro stato, non ci rimane che crearlo!

Per creare lo store utilizzeremo una utility di Redux Toolkit: configureStore:

configureStore è una utility che prende come parametro un oggetto:

Andremo ad utilizzare reducer e middleware nelle prossime puntate, dove parleremo di reducers e sagas, per ora facciamo finta di averli passati alla utility.

Una volta creato lo store bisogna fare in modo che esso sia accessibile all’interno della nostra App. Per farlo utilizzeremo il Provider, un componente esposto dalla libreria react-redux:

Tecnicamente abbiamo fatto, il nostro store è pronto per essere utilizzato all’interno della nostra app.

Continua la serie

Ora che lo store è fruibile e possiamo cominciare ad interagirci, dobbiamo creare i reducer per implementare le logiche per aggiornare lo stato e le action che andranno a triggerare questi reducer.

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 👈 tu sei qui!
  5. Le Action
  6. I Reducer
  7. I Selector
  8. I Middleware
  9. Le Saga
  10. Mini App

--

--

Mauro Erta
VLK Studio

Software Engineer at VLK Studio. Whenever I can, I share something I know here on Medium.