• Non ci sono risultati.

React

1. Montaggio: corrisponde alla prima creazione di un componente, quindi viene eseguita per la prima volta la relativa funzione JavaScript e il

3.4 Stato di un componente

React

const Chapter = (props) => { return (

<div style={{padding: "8px"}}>

<h1>{props.title}</h1>

{props.children}

</div>

);

}

const Section = (props) => { return (

<div style={{paddingBottom: "5px"}}>

<h2>{props.title}</h2>

<p>content....</p>

</div>

);

}

const Thesis = () => { return (

<Chapter title="React">

<Section title="Props"/>

<Section title="Stato di un componente"/>

</Chapter>

);

}

I due componenti Section sono passati come figli all’interno del compo-nente Chapter tramite la props children. Questo meccanismo permette di disaccoppiare il componente Chapter dal suo contenuto rendendolo così più riusabile.

React

"Fino a un po’ di tempo fa, i componenti di classe erano l’unico modo per definire un componente che avesse un proprio stato, e che potesse accedere ai metodi del ciclo di vita in modo da poter eseguire operazioni la prima volta che il componente veniva creato, quando veniva aggiornato o rimosso."[3]

L’introduzione di React Hooks, a partire dal 2019, ha apportato un’impor-tante novità, permettendo la gestione dello stato, della sua evoluzione e l’ese-cuzione di effetti collaterali all’interno di componenti funzionali, rendendoli così molto più potenti.

Gli hooks sono funzioni il cui nome inizia per convenzione con use. Per ogni componente funzionale ne possono essere invocati molteplici e tutti nello stes-so ordine ovvero non posstes-sono essere usati all’interno di un ramo condizionale del codice. Essi sono legati alla singola istanza di un componente, garantendo così l’isolamento tra uno stato ed un altro.

Tra gli hooks presenti all’interno della libreria React, che saranno analizzati in dettaglio nel seguito di questo paragrafo in quanto i più utilizzati, vi sono:

• useState;

• useReducer;

• useContext;

• useEffect;

ma libreria ne mette a disposizione tanti altri tra cui useMemo, useCallback, useRef. Inoltre, per gestire particolari comportamenti o esigenze è possibile definire hooks personalizzati, che danno al programmatore la possibilità di condividere stato e logica applicativa tra i componenti.

3.4.1 useState

È utilizzato per mantenere e gestire lo stato interno del componente che si modifica sulla base di eventi scatenati su alcune parti del componente stesso. useState accetta in ingresso il valore di inizializzazione dell’elemento e restituisce un array di due elementi: la variabile di stato che si aggiorna ad ogni variazione dello stato e la funzione che si utilizza per alterare tale stato. Per accedere agli elementi dell’array si può utilizzare l’assegnamento di destrutturazione come nel seguente esempio in cui si vuole gestire lo stato di un contatore:

React

const [count, setCount] = useState(0);

All’interno di un componente questo hook è richiamabile quante volte si desidera per creare tutte le variabili di stato di cui si necessita.

3.4.2 useReducer

Spesso, nel contesto di applicazioni articolate, lo stato da mantenere potrebbe diventare complesso e problematico: questo accade ad esempio in situazioni in cui l’aggiornamento di una variabile condiziona lo stato di un’altra. Per gestire uno stato articolato si utilizza il meccanismo azioni/riduzioni:

• ogni azione che può scatenare una modifica sullo stato è descritta in un oggetto la cui chiave type ne indica la tipologia;

• il riduttore è una funzione che:

accetta in ingresso lo stato attuale e il tipo dell’azione da eseguire;

restituisce in uscita un nuovo stato modificato sulla base dell’azione indicata.

Il riduttore contiene al suo interno un costrutto del tipo switch (action.type) {...} che in base al tipo di azione specificata, esegue gli step necessari per aggiornare lo stato.

Lo hook utilizzato per realizzare il meccanismo azioni/riduzioni prende il nome di useReducer che:

• accetta due parametri in ingresso: la funzione di riduzione e lo stato iniziale;

• restituisce una lista formata da due elementi: lo stato corrente e il dispatch che è in grado di inviare l’azione corretta alla funzione di riduzione.

Il dispatch, invocato in un componente, richiama la funzione di riduzione, aggiorna lo stato e il componente che lo ha invocato.

React

3.4.3 useContext

Se si vuole condividere lo stato tra più componenti è necessario che esso sia posizionato il più in alto possibile: infatti, ogni stato è condivisibile in direzione top-down con i componenti sottostanti tramite l’utilizzo delle props.

Quando, però, è necessario condividere lo stato con un componente che si trova diversi livelli più in basso la situazione potrebbe complicarsi, perché tutti i figli nel mezzo devono fungere da mezzo di passaggio pur non essendo direttamente interessati al dato che transita al loro interno. Un altro proble-ma emerge quando è necessario condividere lo stato con un componente al di fuori della catena gerarchica.

Per gestire queste situazioni esiste lo hook useContext tramite il quale è possibile passare lo stato e permetterne l’aggiornamento senza dover ricorrere all’utilizzo delle props.

Il funzionamento è il seguente:

• si crea il contesto: const MyContext = React.createContext();

• si crea un componente wrapper che contiene tutti gli elementi che po-tranno accedere al contesto:

<MyContext.Provider value={myContext}>

{children}

</MyContext.Provider>

• per accedere al contesto, all’interno di un componente children si usa il Consumer:

const Child = () => (

<MyContext.Consumer>

{myContext => (<div style={{color: myContext.color}}/>)}

</MyContext.Consumer>

);

Per semplificare l’accesso al contesto dichiarato, al Consumer si preferisce lo hook useContext. Questo hook accetta come parametro il contesto da consumare e restituisce il valore corrente contenuto nel contesto.

const {color} = useContext(MyContext);

L’utilizzo congiunto degli hooks useReducer e useContext permettono di creare uno o più stati complessi e generali per la gestione di un intero applicativo.

React

3.4.4 useEffect

Questo hook è un’implementazione del design pattern Observer e si utilizza per eseguire appunto effetti collaterali ad ogni invocazione di un componente.

Esso accetta due parametri: una funzione e un array che contiene una lista di variabili di stato da osservare. Il comportamento è il seguente: la funzione passata come parametro viene rieseguita dopo ogni render del componente e ogni volta che una variabile osservata cambia valore. Se si vuole far in modo che la funzione venga eseguita solo dopo il primo render è sufficiente passare un array vuoto in questo modo si ha la certezza che la funzione non sarà più eseguita.

useEffect((function), [var1, var2, ..., varN]);

Documenti correlati