
GUIDE PER ASPIRANTI PROGRAMMATORI
Introduzione agli stati globali in React
Torniamo alle origini con le proprietà e gli eventi. Abbiamo visto, ormai, davvero moltissimi esempi del passaggio dei dati in React: i dati viaggiano sempre in una direzione, dai componenti genitori ai figli. I valori dei dati viaggiano tramite props, mentre gli eventi vanno nella direzione opposta. Molto spesso i valori coincidono con degli stati…


Vuoi avviare una nuova carriera o fare un upgrade?
Trova il corso Digital & Tech più adatto a te nel nostro catalogo!
Torniamo alle origini con le proprietà e gli eventi.
Abbiamo visto, ormai, davvero moltissimi esempi del passaggio dei dati in React: i dati viaggiano sempre in una direzione, dai componenti genitori ai figli. I valori dei dati viaggiano tramite props, mentre gli eventi vanno nella direzione opposta. Molto spesso i valori coincidono con degli stati e gli eventi chiamano funzioni setter.
Ci sono dei casi in cui lo stato e la funzione setter vengono definiti a un livello molto diverso da quello in cui vengono usati, nel senso che, tra il componente che definisce lo stato e quello che ne mostra il valore o ne notifica i cambiamenti, ci sono componenti figli di figli di figli di figli…
Prop drilling in React
Nei casi appena descritti si parla di prop drilling (“trapanamento” di proprietà). Noi sappiamo che dobbiamo cercare di spostare la logica (i nostri componenti controller) il più possibile vicino ai componenti che la utilizzano (i componenti view). Ma questa cosa non è sempre fattibile e, soprattutto, alcuni sviluppatori preferiscono concentrare tutta la logica in un unico punto: se uno di questi sviluppatori dovesse essere il nostro capo e non potessimo convincerlo a fare altrimenti, dovremmo adottare anche noi lo stesso approccio.
Nota: la strategia di avere tanti componenti controller e di metterli il più possibile vicino ai loro componenti view non è una questione di preferenze e opinioni personali. Un’applicazione che ha – estremizzando- un solo componente controller che contiene tutta la logica, conterrà difficilmente componenti riutilizzabili. Inoltre, per via del funzionamento di React, ogni cambiamento di stato causerà il rendering dell’intera applicazione. È vero che i componenti view sono, genericamente, più riutilizzabili dei componenti controller, per cui un’applicazione che contiene più componenti view (come quella che ha un unico controller) dovrebbe avere più componenti riutilizzabili, ma difficilmente è così. È molto più probabile che, per gestire il funzionamento delle varie parti del sistema, i componenti view diventino comunque specializzati, finendo per ottenere l’effetto contrario. Se dovessi trovarti ad avere a che fare con componenti che hanno nomi legati a concetti, come UserAgeInput, probabilmente staresti per avere proprio questo problema. Dall’altro lato, progettando il sistema per dividere la logica in più punti, si ha a che fare con funzionalità più semplici ed è più facile individuare parti in comune. Facendo uso delle funzioni hook per isolare e riutilizzare la logica, resteranno solo i dati specifici, come nel caso del nostro componente TodoItemForm, e componenti view legati al tipo di dato da gestire, con nomi come NonNegativeIngeterInput.
Il problema del prop drilling avviene anche quando si utilizzano concetti molto generici, come, per esempio, il tema dell’applicazione (che sia chiaro/scuro, o più personalizzabile), la lingua su cui si basano tutte le traduzioni, o una configurazione che un utente può scegliere e che modifica il comportamento dell’intera applicazione.
In questi casi, se utilizzassimo solo gli strumenti che abbiamo visto fino ad ora, ci troveremmo a passare prop ed eventi attraverso la struttura dei componenti, per usarli magari nei componenti view in fondo alla struttura.
Per esempio, la lingua scelta dall’utente potrebbe servirci attraverso tutta l’applicazione, ma l’evento che segnala il cambiamento della lingua potrebbe essere scatenato da un menù a tendina in una sezione molto specifica dell’applicazione. In questo caso ci troveremmo ad avere a che fare con una struttura del genere:
<App> <Router language={language} onLanguageChange={onLanguageChange}> <ProfilePage language={language} onLanguageChange={onLanguageChange}> <Settings language={language} onLanguageChange={onLanguageChange}> <Panel language={language} onLanguageChange={onLanguageChange}> <Select value={language} onChange={onLanguageChange} /> </Panel> </Settings> </ProfilePage> </Router> </App>
In questo esempio abbiamo un ipotetico stato che rappresenta la lingua scelta dall’utente dichiarato dentro App:
// Nel componente App const [language, setLanguage] = useState(/* ... */);
Il menù per scegliere la lingua è dentro un componente Select, figlio di Panel, figlio di Settings, figlio di ProfilePage, figlio di Router, figlio di App. Per far arrivare il nostro valore dello stato language e la funzione onLanguageChange che chiama la funzione setter setLanguage, dobbiamo passare entrambi come props per tutti i componenti intermedi! Alcuni di quei componenti potrebbero usare il valore dello stato language, ma nessuno di loro userà onLanguageChange.
Se immaginiamo questa situazione ripetersi per tutte le prop che ci servono un po’ dappertutto, è facile capire come ci si potrebbe ritrovare con componenti controller che scambiano molte più prop di quelle che usano, solo perché devono fare la staffetta con i loro genitori per passare props ai figli. Questo è il problema del prop drilling.
React ci permette di risolvere questo problema tramite la funzione hook useContext e il concetto di Context in generale.
CONTENUTI GRATUITI IN EVIDENZA
Guide per aspiranti programmatori 👨🏻🚀
Vuoi muovere i primi passi nel Digital e Tech? Abbiamo preparato alcune guide per aiutarti a orientarti negli ambiti più richiesti oggi.