CONTATTACI

Guide per aspiranti programmatori

Lezione 31 / 41

Gli effetti collaterali in React

Abbiamo detto che le funzioni pure ci regalano riutilizzabilità, componibilità e confidenza, ma non possiamo rinunciare agli effetti collaterali: avremo sempre bisogno di salvare dati, mandare richieste di rete, modificare strutture di dati.

React prevede due momenti in cui possiamo eseguire effetti collaterali, uno per React e uno per noi:

  1. Il rendering: l’attività con cui React modifica il DOM (gli elementi HTML) per visualizzare il nostro codice JSX, è un effetto collaterale. Quello che fanno i nostri componenti è trasformare props e/o stati in JSX, dopodiché, alla fine di ogni ciclo di rendering, React applica l’effetto collaterale di inserire gli elementi derivati da JSX nella pagina HTML.
  2. Le funzioni hook: le funzioni setter restituite da useState rappresentano effetti collaterali. I nostri hook useQuery e useCommand rappresentano effetti collaterali, per cui, oltre a trasformare le props e gli stati in JSX, lanciamo delle chiamate di rete.

Gli effetti collaterali – che in programmazione imperativa possono essere anche il 100% del codice – sono i più difficili da individuare per le persone non abituate alla programmazione dichiarativa. Per fortuna, in React, essendo i componenti stessi funzioni, è più facile rispondere alle domande “il mio componente fa qualcos’altro oltre a trasformare le props e gli stati in JSX? Se sì, ho isolato gli effetti collaterali dentro funzioni hook?”.

Ora che sappiamo cosa sono gli effetti collaterali, possiamo vedere il prossimo hook incluso in React, creato apposta per eseguire effetti collaterali: useEffect.

 

useEffect in React

Come abbiamo appena accennato, useEffect è la funzione hook che React ci fornisce per applicare effetti collaterali all’interno dei nostri componenti. Questa è la sintassi generica di useEffect:

 

useEffect(
  () => {
    // side effect

    // optional
    return () => {
      // cleanup
    };
  },
  [
    /* dependencies */
  ]
);

useEffect è una funzione che accetta due argomenti:

  1. La funzione che rappresenta l’effetto collaterale. Questa funzione non può avere un valore di ritorno (in altre parole, deve restituire void). Gli effetti collaterali non restituiscono mai un valore perché, per definizione, fanno qualcosa di slegato dal resto del sistema. La funzione che passiamo come primo argomento di useEffect può restituire una seconda funzione, che possiamo chiamare cleanup function (in italiano, funzione di pulizia). La cleanup function è una funzione che rimuove eventuali effetti collaterali persistenti. Per esempio:
    useEffect(() => {
      const onWindowResize = () => {
        console.log("The window has been resized!");
      };
    
      window.addEventListener("resize", onWindowResize);
    
      return () => {
        window.removeEventListener("resize", onWindowResize);
      };
    }, []);

    In questo esempio, ascoltiamo l’evento nativo del browser che scatta quando la finestra viene ridimensionata. La nostra cleanup function smette di ascoltare. Non siamo costretti a restituire una cleanup function, possiamo anche non restituire niente. Quando applichiamo un effetto permanente, però, per esempio, appunto, ascoltare un evento, restituiamo una cleanup function, altrimenti continueremmo ad ascoltare l’evento anche dopo che il componente è stato rimosso dalla pagina, creando errori e sprecando risorse del browser.

     

  2.  Un array di dipendenze. Le dipendenze sono le props o gli stati che devono scatenare l’effetto collaterale in caso di aggiornamento. Per esempio:

    export default function Profile({ authStatus }) {
      useEffect(() => {
        authStatus.match({
          whenAnonymous: () => {
            window.localStorage.removeItem("auth");
          },
          whenLoggedIn: (credentials) => {
            window.localStorage.setItem(
              "auth",
              JSON.stringify(authStatus.credentials)
            );
          },
        });
      }, [authStatus]);
    }

    In questo esempio, immaginiamo di avere uno stato, da qualche parte in un componente controller, che rappresenta lo stato di autenticazione dell’utente. authStatus fornisce una funzione di matching che ha due stati: “anonimo” (“anonymous“) e “autenticato” (“logged_in“).

     

    Quando l’utente è autenticato, la funzione di matching di authStatus fornisce la proprietà credentials, che contiene le credenziali di autenticazione dell’utente, come il token di autenticazione (mai salvare la password da nessuna parte!).

    Lo stato di autenticazione viene passato al nostro componente view Profile, che salva le credenziali nell’archivio locale del browser se l’utente è autenticato, altrimenti (se è anonimo) le elimina. In questo caso, il nostro effetto collaterale deve essere eseguito ogni volta che lo stato di autenticazione viene aggiornato, così che possiamo reagire a login e logout eseguendo le operazioni corrette.

    Aggiungiamo, quindi, authStatus all’array delle dipendenze dell’effetto, così che React esegua la funzione ogni volta che viene chiamata la funzione setter dello stato che si trova nel componente controller, e di conseguenza la prop viene aggiornata.

     

Attenzione: anche in questo caso, come per i cicli di rendering, non è esatto dire che gli effetti vengono eseguiti quando le cose cambiano. Gli effetti vengono eseguiti ogni volta che viene chiamata la funzione setter dello stato corrispondente alla nostra dipendenza, anche se il prossimo valore dello stato è identico a quello corrente. Tutti gli effetti, a prescindere dalle loro dipendenze, vengono anche eseguiti quando il componente che li contiene viene creato.

 

Le dipendenze degli effetti in React

La regola di React per le dipendenze degli effetti è questa: tutte le variabili che vengono citate all’interno della funzione che rappresenta l’effetto (quella che passiamo come primo argomento a useEffect) devono essere inserite tra le dipendenze, tranne le funzioni setter degli stati.

Attenzione: se una prop è, in realtà, una funzione setter passata dal componente controller, non vale come funzione setter, va comunque inclusa tra le dipendenze. Le uniche funzioni setter che si possono omettere sono quelle che fanno riferimento a stati nello stesso componente in cui usiamo useEffect.

React, attraverso ESLint, ci darà un avvertimento se una delle variabili citate all’interno della funzione che rappresenta l’effetto non fa parte delle dipendenze, o se ne abbiamo messe di troppo. Ci dirà anche che possiamo aggiungere un commento nella riga di codice precedente a quella in cui abbiamo dichiarato le dipendenze, per spegnere l’avvertimento: non farlo mai. Nel 99% dei casi, se una variabile citata all’interno della funzione che rappresenta l’effetto non fa parte delle dipendenze, significa che c’è un errore di logica nel modo in cui stiamo progettando il sistema.

 

Il ciclo di rendering di React e gli effetti collaterali

Sappiamo come funziona il ciclo di rendering di React quando abbiamo a che fare con props, stati ed eventi:

  1. Al primo ciclo di rendering, tutte le funzioni che rappresentano i componenti in pagina vengono eseguite con i loro stati iniziali.
  2. Quando un evento scatena la chiamata di una funzione setter, tutti i componenti che usano lo stato che è cambiato, e tutti i loro figli, vengono chiamati al rendering con il nuovo valore dello stato.

Ma come si comporta React con gli effetti collaterali? Gli effetti collaterali vengono eseguiti dopo il ciclo di rendering:

  1. Tutti gli effetti collaterali che dipendono dallo stato che è cambiato vengono eseguiti. 

Nella prossima sezione, analizzeremo una serie di casi in cui l’uso di effetti collaterali è sconsigliato, e il fatto che scatenino cicli di rendering è uno dei motivi per cui lo è.

Contattaci senza impegno per informazioni sul corso

Pagamento rateale

Valore della rata: A PARTIRE DA 115 €/mese.

Esempio di finanziamento 

Importo finanziato: € 2440 in 24 rate da € 115 – TAN fisso 9,55% TAEG 12,57% – importo totale del credito € 2841.

Il costo totale del credito comprende: interessi calcolati al TAN indicato, oneri fiscali (imposta di bollo sul contratto 16,00 euro*) addebitati sulla prima rata, costo mensile di gestione pratica € 3,90, spesa di istruttoria € 0,00, spesa per invio rendicontazione periodica cartacea € 0,98 (o spesa per invio rendicontazione periodica cartacea € 0,00), imposta di bollo su rendicontazione periodica € 0,00. Modalità di rimborso obbligatoria: addebito diretto su c/c. La scadenza delle rate è determinata dal giorno della liquidazione del contratto; la data di scadenza delle rate è prevista il giorno 15 del mese. L’importo di ciascuna rata comprende una quota di capitale crescente e interessi decrescente secondo un piano di ammortamento “alla francese”. Offerta valida dal 01/01/2024 al 31/12/2024.

Messaggio pubblicitario con finalità promozionale. Per le informazioni precontrattuali richiedere sul punto vendita il documento “Informazioni europee di base sul credito ai consumatori” (SECCI) e copia del testo contrattuale. Salvo approvazione di Sella Personal Credit S.p.A. Aulab S.r.l. opera quale intermediario del credito NON in esclusiva.

*In fase di richiesta del finanziamento verrà proposta la facoltà di selezionare, in alternativa all’imposta di bollo sul contratto di 16,00 euro, l’imposta sostitutiva, pari allo 0,25% dell’importo finanziato.

Pagamento rateale

Valore della rata: A PARTIRE DA 210 €/mese.

Esempio di finanziamento  

Importo finanziato: € 4500 in 24 rate da € 210,03 – TAN fisso 9,68% TAEG 11,97% – importo totale del credito € 5146,55.

Il costo totale del credito comprende: interessi calcolati al TAN indicato, oneri fiscali (imposta di bollo sul contratto 16,00 euro*) addebitati sulla prima rata, costo mensile di gestione pratica € 3,90, spesa di istruttoria € 0,00, spesa per invio rendicontazione periodica cartacea € 0,98 (o spesa per invio rendicontazione periodica cartacea € 0,00), imposta di bollo su rendicontazione periodica € 0,00. Modalità di rimborso obbligatoria: addebito diretto su c/c. La scadenza delle rate è determinata dal giorno della liquidazione del contratto; la data di scadenza delle rate è prevista il giorno 15 del mese. L’importo di ciascuna rata comprende una quota di capitale crescente e interessi decrescente secondo un piano di ammortamento “alla francese”. Offerta valida dal 01/01/2024 al 31/12/2024.

Messaggio pubblicitario con finalità promozionale. Per le informazioni precontrattuali richiedere sul punto vendita il documento “Informazioni europee di base sul credito ai consumatori” (SECCI) e copia del testo contrattuale. Salvo approvazione di Sella Personal Credit S.p.A. Aulab S.r.l. opera quale intermediario del credito NON in esclusiva.

* In fase di richiesta del finanziamento verrà proposta la facoltà di selezionare, in alternativa all’imposta di bollo sul contratto di 16,00 euro, l’imposta sostitutiva, pari allo 0,25% dell’importo finanziato.

Contattaci senza impegno per informazioni sul corso

Scopriamo insieme se i nostri corsi fanno per te. Compila il form e aspetta la chiamata di uno dei nostri consulenti.