Articolo originale: React State for Absolute Beginners di Reed Barger

Tradotto e adattato da: Angelo Mirabelli

Uno dei concetti più essenziali che qualsiasi sviluppatore JavaScript moderno deve comprendere è lo stato.

Se non capisci lo stato, non sarai in grado di utilizzare e sfruttare appieno le potenti librerie come React per costruire le tue applicazioni.

Vediamo esattamente cosa è lo stato, come esiste già ora nelle tue applicazioni JavaScript e come React ci consente di gestirlo molto più facilmente con gli hook integrati come useState.

Cos'è lo stato?

Qualcosa che potrebbe sorprenderti è che qualsiasi sito Web o applicazione che crei con semplice JavaScript coinvolge già lo stato, anche se non è ovvio dove vive.

Ecco un semplice esempio:

Diciamo che stiamo costruendo un'applicazione contatore con JavaScript. Vogliamo che questa applicazione sia in grado di visualizzare il conteggio corrente e di aumentare e diminuire il conteggio di uno.

Consisterà solo nel conteggio corrente e in due pulsanti che rispettivamente aumentano e diminuiscono il conteggio di uno.

Ecco come apparirà la versione finale della nostra app:

image-2
L'app contatore finita

Ecco il markup iniziale per la nostra applicazione:

<!DOCTYPE html>
<html>
  <head>
    <title>Counter App</title>
    <meta charset="UTF-8" />
  </head>

  <body>
    <div>
      <button>+ 1</button>
      <span>0</span>
      <button>- 1</button>
    </div>
  </body>
</html>

In poche parole, lo stato sono i dati che dobbiamo gestire nel tempo all'interno della nostra applicazione.

Lo stato viene spesso modificato tramite l'input dell'utente come in questo caso, all'interno della nostra applicazione.

Qual è lo stato nella app contatore? È il numero del conteggio.

L'utente può aumentare o diminuire il valore dello stato facendo clic sull'apposito pulsante. La cosa importante è che vogliamo mostrare queste modifiche al nostro utente.

Problemi con lo stato in JavaScript semplice

Sebbene lo stato sembri un concetto semplice, ci sono due problemi con la sua gestione quando si utilizza solo normale JavaScript:

  1. Non è ovvio cosa sia lo stato o dove viva.
  2. La lettura e l'aggiornamento dello stato sono un processo innaturale e spesso ripetitivo quando si utilizzano API browser native come document.

Come faremmo per aggiornare lo stato del contatore quando l'utente fa clic su uno dei pulsanti?

Per prima cosa dobbiamo ottenere un riferimento a ciascun elemento. Per fare ciò in normale JavaScript, è pratica comune aggiungere un attributo id univoco a ciascun elemento, selezionare ogni elemento in JavaScript con il metodo document.querySelector e memorizzare il riferimento in una variabile locale:

<!DOCTYPE html>
<html>
  <head>
    <title>Counter App</title>
    <meta charset="UTF-8" />
  </head>

  <body>
    <div>
      <button id="increment">+ 1</button>
      <span id="count">0</span>
      <button id="decrement">- 1</button>
    </div>

    <script>
      const increment = document.querySelector("#increment");
      const count = document.querySelector("#count");
      const decrement = document.querySelector("#decrement");
    </script>
  </body>
</html>

Ora che abbiamo i riferimenti a ogni elemento HTML, come facciamo a far funzionare il pulsante di incremento?

Per prima cosa dobbiamo ascoltare un evento di clic sul nostro pulsante di incremento. Quindi, quando si fa clic sul pulsante, è necessario ottenere il valore di conteggio corrente dall'elemento con id "count".

Per fare ciò, ci immergiamo nel documento HTML usando l'API document e otteniamo quel valore con count.innerText. Il valore innerText è una stringa, quindi lo convertiamo in un numero, aggiungiamo 1 e riscriviamo quel valore in count.innerText .

Per far funzionare il pulsante di decremento, eseguiamo nuovamente gli stessi passaggi con la differenza che usiamo l'espressione Number(count.innerText - 1).

<!DOCTYPE html>
<html>
  <head>
    <title>Counter App</title>
    <meta charset="UTF-8" />
  </head>

  <body>
    <div>
      <button id="increment">+ 1</button>
      <span id="count">0</span>
      <button id="decrement">- 1</button>
    </div>

    <script>
      const increment = document.querySelector("#increment");
      const count = document.querySelector("#count");
      const decrement = document.querySelector("#decrement");

      increment.addEventListener("click", () => {
        count.innerText = Number(count.innerText) + 1;
      });

      decrement.addEventListener("click", () => {
        count.innerText = Number(count.innerText) - 1;
      });
    </script>
  </body>
</html>

Non sono molte righe di codice, ma qui puoi vedere che ci sono una serie di passaggi che sono ripetitivi e altri che non sono molto intuitivi:

  • Aggiungere un ID arbitrario agli elementi HTML
  • Eseguire una query per l'elemento utilizzando JavaScript
  • Memorizzare il riferimento all'elemento nella variabile
  • Ascoltare l'evento appropriato sull'elemento
  • Ottenere il valore dello stato corrente utilizzando l'API document
  • Riscrivere il nuovo valore di stato nella pagina con .innerText

Queste sono le molte istruzioni di basso livello necessarie per il funzionamento del programma, ma non ci aiutano a pensare allo stato sottostante.

Come abbiamo visto, lo stato vive nel browser. Ciò significa che dobbiamo prima "trovare" lo stato e poi imperativamente (in un modo che il computer capisce meglio di noi) aggiornare quel valore.

Fortunatamente, React ci offre un modo molto più semplice per aggiornare lo stato e pensare allo stato.

In che modo React ci aiuta a gestire lo stato?

Un vantaggio significativo nell'utilizzo di React e il motivo per cui è nel tuo interesse utilizzare React per sviluppare le tue applicazioni JavaScript è che offre schemi molto più semplici per aggiornare lo stato.

A differenza del normale JavaScript, React si occupa del difficile lavoro di aggiornare ciò che l'utente vede. Tutto quello che dobbiamo fare è dirgli quale stato stiamo gestendo e quale dovrebbe essere il nuovo valore.

Invece di avere lo stato che vive all'interno del browser e doverlo trovare ogni volta che dobbiamo leggerlo o aggiornarlo, possiamo semplicemente inserirlo in una variabile e quindi aggiornare il valore di quella variabile. Dopo averlo fatto, l'aggiornamento e il nuovo valore verranno visualizzati agli utenti.

Questo è l'intero concetto di gestione dello stato in React.

Invece di usare un documento HTML, possiamo scrivere tutto il nostro markup all'interno di un componente React.

È scritto in modo identico a una normale funzione JavaScript e visualizza gli stessi elementi HTML utilizzando una sintassi identica chiamata JSX.

export default function Counter() {
  return (
    <div>
      <button>+ 1</button>
      <span>0</span>
      <button>- 1</button>
    </div>
  );
}

Come possiamo fare la stessa applicazione contatore con React?

Nell'app React, una volta identificato qual è lo stato, lo controlliamo utilizzando una variabile JavaScript.

Questa variabile può essere dichiarata in molti modi. Il modo più diffuso per gestire lo stato dei componenti è con l'hook useState .

Un hook in React funziona in modo molto simile alle normali funzioni JavaScript. Ciò significa che possiamo richiamarlo nella parte superiore del nostro componente e passargli il valore predefinito come valore iniziale per la nostra app contatore.

Poiché il valore iniziale del nostro valore di conteggio è zero, chiamiamo semplicemente il nostro hook e gli passiamo il valore 0 e quel valore viene inserito nella nostra variabile di stato.

import { useState } from 'react';

export default function Counter() {
  // il valore count vive ed è gestito qui!
  const [count] = useState(0);  
    
  return (
    <div>
      <button>+ 1</button>
      <span>{count}</span> {/* usa le parentesi graffe per aggiungere il valore di count in JSX: 0 */}
      <button>- 1</button>
    </div>
  );
}

Non c'è più bisogno di usare count.innerText. Possiamo semplicemente stampare e leggere il valore del nostro stato usando count.

Proprio come qualsiasi variabile JavaScript, possiamo nominarla come vogliamo, non deve essere necessariamente chiamata count: potresti  letteralmente chiamarla con qualsiasi altra parola purché sia ​​un nome JavaScript valido.

Il valore restituito da useState è un array, quando lo destrutturiamo, il primo valore destrutturato è la variabile di stato. il secondo è la funzione per aggiornare lo stato.

import { useState } from 'react';

export default function Counter() {
  const [count, setCount] = useState(0);  
    
  return (
    <div>
      <button>+ 1</button>
      <span>{count}</span>
      <button>- 1</button>
    </div>
  );
}

Come facciamo a far funzionare il pulsante di incremento?

Ecco cosa non dobbiamo fare:

  • Non abbiamo bisogno di aggiungere un id agli elementi HTML
  • Non abbiamo bisogno di esaminare il DOM e capire quale pulsante è
  • Non è necessario ascoltare un evento di clic con document.addEventListener

Per aggiornare lo stato quando fai clic su un pulsante, aggiungi la prop onClick a ciascun pulsante, in questo modo puoi chiamare una funzione quando il pulsante viene premuto dall'utente.

Per il pulsante di incremento, aggiorneremo lo stato passando count + 1 a setCount, e per il pulsante di decremento, passeremo count - 1 a setCount.

import { useState } from 'react';

export default function Counter() {
  const [count, setCount] = useState(0);  
    
  function incrementCount() {
    setCount(count + 1);
  }
    
  function decrementCount() {
    setCount(count - 1);   
  }
    
  return (
    <div>
      <button onClick={incrementCount}>+ 1</button>
      <span>{count}</span>
      <button onClick={decrementCount}>- 1</button>
    </div>
  );
}

Questo è tutto il codice di cui abbiamo bisogno per creare un'app contatore funzionante con React.

Quando ogni pulsante viene premuto e lo stato viene aggiornato, React eseguirà tutto il lavoro di aggiornamento della pagina in modo che l'utente possa vedere il nuovo stato.

Questo è il grande vantaggio dell'utilizzo di React rispetto al normale JavaScript: quando lo stato è gestito utilizzando hook come useState e React si occupa di aggiornare in modo efficiente ciò che l'utente vede, possiamo creare app più semplici e affidabili in cui lo stato è facile da vedere, leggere e aggiornare.