Redux - fromScarso2King - 7 - I Selector

Se selezionando… io potessi non ri-renderizzarti, ti selezionerei

Mauro Erta
VLK Studio
5 min readJan 4, 2021

--

Arrivati a questo punto abbiamo:

  1. Uno store fruibile dalla nostra applicazione;
  2. Delle action pronte per essere dispatchate;
  3. Dei reducer per aggiornare lo stato applicativo in funzione delle action;

Ci manca però un punto fondamentale, forse il più importante, usare lo stato nelle nostre componenti!

Portare lo stato nella UI

Rinfreschiamoci la memoria sul modello Redux:

La parte bassa del grafico mostra come le componenti siano collegate allo stato, in particolare si “sottoscrivono” allo store, che significa?

Significa quando c’è un aggiornamento dello stato, lo store segnala alle componenti il cambiamento inducendole ad un nuovo render; La UI in questo modo verrà aggiornata con i nuovi dati presenti nello stato

Per prima cosa quindi dobbiamo connettere le componenti allo stato, per farlo esistono 2 modi:

Modo old school

Per i più nostalgici esiste un hoc della libreria react-redux che permette di connettere la componente allo stato:

Questo hoc è il connect, ed è già stata introdotto nella puntata relativa alle actions; Serve ad iniettare all’interno del componente lo stato applicativo e le funzioni per dispatchare le action, viene usata specificando due parametri, tipicamente indicati come mapStateToProps e mapDispatchToProps.

In questo caso ci interessa il primo parametro della connect (mapStateToProps) che è una funzione che ha come parametri lo stato applicativo e le prop del componente, restituisce un oggetto che verrà unito con le prop del componente per mezzo di fusione:

Quindi se le prop iniziali del componente fossero:

utilizzando la mapStateToProps avremo:

Potremmo quindi utilizzare la nuova prop article all’interno del componente.

Metodo new school

Adesso fortunatamente ci sono gli hooks, che semplificano parecchio l’iniezione dello stato all’interno delle componenti:

Molto più semplice e conciso! Notate come questa soluzione è il 25% più piccola della precedente, ma in un caso reale questa percentuale crescerebbe ulteriormente.

In questo caso per iniettare lo stato utilizziamo l’hook useSelector, importato anch’esso da react-redux, questo hook prende come parametro una callback, questa callback riceverà lo stato come argomento e restituirà la porzione di stato desiderata (nel nostro caso, l’articolo).

L’importanza di chiamarsi Spider Man

Che si scelga la vecchia o la nuova scuola, c’è una cosa che accomuna entrambe le soluzioni:

Lo stato non viene passato direttamente al componente, ma viene piuttosto passata al componente solamente una porzione di esso:

Perché? Non sarebbe più semplice passare tutto lo stato al componente?

Come abbiamo detto all’inizio dell’articolo, le componenti reagiscono ai cambiamenti dello stato una volta connesse ad esso, e questo potrebbe essere un grosso problema in ottica ottimizzazione del render!

Come dice spider man (o forse lo zio? 🤷🏻‍♂️):

da grandi poteri derivano grandi responsabilità

Ogni volta che non usi i selector, spider man piange

Se non facciamo attenzione infatti rischiamo di ri-renderizzare le componenti ogni volta che lo stato cambia, anche se il cambiamento non ha implicazioni dirette sulla componente stessa. Facciamo un esempio:

Ho preparato un CodeSandbox dove è possible testare questo fenomeno:

Provate ad andare nel file Article.jsx e vedrete:

Provate a cliccare sul tasto `+` e guardate la console dei log.

Ogni volta che il counter viene incrementato il componente Article ri-renderizza(vedrete il log “render” ripetersi). Eppure nel componente Article non c’è nessun riferimento a counter.

Provate ora a de-commentare la parte di sotto indicata come GOOD e commentare la porzione indicata come BAD e riprovate il test, come vedi il componente non ri-renderizza più!

Performance STONKS

Okay ma… cosa sono i selector?

I Selector

Un selector altro non è che una funzione che prende lo stato applicativo come input e restituisce una porzione, o una manipolazione, di esso come output.

Prendiamo l’esempio precedente:

La parte evidenziata è a tutti gli effetti un selector, anche se normalmente i selector non vengono definiti così, cioè inline all’interno del componente, ma piuttosto in file separati ed utilizzando dei tool che permettono di comporli ed ottimizzarli. Per questo nella puntata 3 della serie abbiamo predisposto una cartella selectors.

I selector in altre parole sono quelle funzioni che prelevano i dati dallo stato per fornirli all’interfaccia.

Quando abbiamo bisogno di ricevere dati nelle componenti, magari formattati in maniera particolare, è sempre un ottima idea creare un selector che vada a selezionare i dati esattamente come li vogliamo in interfaccia, così da poter distinguere il modo in cui salviamo i dati nello stato ed il modo in cui li presentiamo.

Per creare selector agilmente ci viene incontro una utility esposta da Redux toolkit detta createSelector.

Creare Selector

Questa utility è in realtà fornita da una libreria separata detta reselect, per comodità però viene ri-esportata da redux toolkit.

Questa utility offre 2 grandi vantaggi:

  1. memoizzazione
  2. composizione

Il vantaggio della memoizzazione è banalmente dovuto al fatto che se lo stato non è cambiato non vado a computare nuovamente il selector ma restituisco la computazione già effettuata, STONKS pure in questo caso.

Sulla composizione invece possiamo dire che un selector può essere usato come input per un altro selector!

Un selector, dentro un selector, dentro selector, dentro un …

Penso sia esplicativo fare un esempio. Supponiamo di volere un selector che restituisca tutti gli articoli di una determinata persona:

Il selector potrebbe essere:

Vediamo però come possiamo pensare di scomporre questo selector in più selector così da sfruttare la composizione:

Il vantaggio di questa forma è che scomponendo i vari selector potrò successivamente riutilizzarli per costruire altri selector, oltre a permettere una più efficiente memoizzazione.

All’interno del componente potremmo in seguito utilizzare il selector tramite l’hook useSelector come visto precedentemente:

Continua la serie

I selector ci permettono di accedere allo stato in maniera efficiente dalle componenti, possiamo finalmente vedere i dati nelle interfacce! Per concludere il giro manca solo un pezzo, come facciamo ad ottenere dati da servizi esterni? lo scopriamo nella prossima puntata con i middleware!

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
  7. I Selector 👈 tu sei qui!
  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.