L'hook useState: una guida completa a PlatoBlockchain Data Intelligence. Ricerca verticale. Ai.

Il gancio useState – Una guida completa

Che cos'è uno stato?

Prima di immergerci in profondità nell'hook useState, comprendiamo innanzitutto il termine stato.

Lo stato rappresenta informazioni su qualcosa in un dato momento.

Ad esempio, consideriamo una casella di testo.

Inizialmente, non c'è nulla all'interno di questa casella di testo, quindi il suo stato è vuoto. Supponiamo di iniziare a digitare Hello al suo interno, per ogni tasto premuto lo stato della casella di testo cambierà. All'inizio sarà "H", poi "He", poi "Hel" e così via finché non diventa "Hello".

Inoltre, nota che mentre digiti non perdi il valore precedente. Se premi "H" seguito da "e" otterrai "He" e non solo "e". In altre parole puoi pensare allo stato come al memoria della casella di testo.

La necessità di uno stato in un componente React.

Capiamolo con l'aiuto di un esempio.

Codesanbox senza stato

Qui abbiamo un Fai clic su Contatore componente che visualizza il numero di volte in cui è stato fatto clic sul pulsante Incremento.

Stiamo usando a variabile locale "contatore" per tenere il conto dei clic.

Ogni volta che clicchiamo sul pulsante Incremento, manigliaClick funzione verrà richiamata. Questa funzione aumenterà il valore del contatore di 1 e registrerà anche il valore nella console.

Vai avanti, fai clic sul pulsante Incremento nell'anteprima di CodeSandbox.

Non è successo niente?

Bene, la nostra logica sembra essere corretta. Il valore registrato nella console (CodeSandbox) si aggiorna correttamente ogni volta che facciamo clic, ma perché questo aggiornamento non si riflette nell'interfaccia utente?

È a causa del modo in cui React funziona.

  • Le modifiche alle variabili locali non attivano un nuovo rendering.
  • Durante un re-rendering, un componente viene creato da zero, cioè la funzione di un componente (in questo esempio è la funzione ClickCounter) viene eseguita ancora una volta. Poiché le variabili (ad esempio, contatore) sono locali alla funzione, i loro valori precedenti vengono persi.

Quindi, come facciamo a far ricordare al componente i valori tra i rendering?

Si, hai capito bene! Lo facciamo con l'aiuto del useState gancio.

L'hook useState

L'hook useState fornisce meccanismi per preservare lo stato e attivare un nuovo rendering.

Diamo un'occhiata al suo utilizzo.

import React, { useState } from "react";
const state = useState(initialValue);

// OR

const state = React.useState(initialValue);

L'hook useState restituisce un array che contiene due elementi:

  • A variabile di stato che mantiene i suoi valori durante i re-rendering. Il valore iniziale passato a useState viene assegnato alla variabile state durante il primo rendering.
  • A funzione setter che aggiorna la variabile di stato e attiva anche un nuovo rendering.
const state = useState(0);
const data = state[0];
const setData = state[1];

utilizzando destrutturazione dell'array , possiamo rifattorizzare le affermazioni di cui sopra in un'unica istruzione, come mostrato di seguito:

const [data, setData] = useState(0);

Il valore iniziale passato a useState viene utilizzato solo durante il primo rendering. Per i re-rendering, viene ignorato.

Contatore con useState

Aggiorniamo ora il precedente esempio di contatore per includere l'hook useState.

  • Dal momento che abbiamo bisogno del controvalore tra i re-rendering, convertiamolo in uno stato.
const [counter, setCounter] = useState(0);
  • Chiamata setCounter all'interno della funzione handleClick.
const handleClick = () => {
  setCounter(counter + 1);
  console.log(`%c Counter:${counter}`, "color:green");
};

La funzione setCounter aggiornerà il valore del contatore di 1 e attiverà un nuovo rendering. Quando la funzione del componente viene richiamata durante il re-rendering, la variabile di stato restituita da useState avrà il valore aggiornato.

Prova CodeSandbox con il codice aggiornato. Fai clic sul pulsante Incremento e osserva la magia di useState in azione.

Codesanbox con useState

Puoi verificarlo su un nuovo rendering, il componente funzionale Fai clic su Contatore viene richiamato nuovamente visualizzando i log della console. Il registro "ClickCounter start" che viene aggiunto all'inizio del componente verrà registrato su ogni rendering.

primo rendering

ri-renderizzare

Funzione di aggiornamento

Supponiamo di voler aumentare il valore del contatore di 4 ad ogni clic.

const handleClick = () => {
  setCounter(counter + 1);
    setCounter(counter + 1);
    setCounter(counter + 1);
    setCounter(counter + 1);
    console.log(`%c Counter:${counter}`, "color:green");
    };

Supponiamo che il valore iniziale di counter sia 0. Cosa ti aspetti di vedere una volta cliccato il pulsante?

Senza funzione di aggiornamento

Ti aspettavi che il conteggio fosse 4 giusto? Ma perché invece vedi 1?

a) Ogni rendering è associato a uno stato. Il valore di quello stato rimane bloccato per tutta la durata di quel rendering.

Si noti che il registro all'interno della funzione handleClick stampa il valore del contatore come 0.

Non importa quante volte chiami il metodo setCounter, il valore di counter rimane lo stesso.

const handleClick = () => {
  setCounter(counter + 1);
    setCounter(counter + 1);
    setCounter(counter + 1);
    setCounter(counter + 1);
    console.log(`%c Counter:${counter}`, "color:green");
    };
b) Fino a quando tutto il codice all'interno di un gestore di eventi non viene eseguito, React non attiverà un nuovo rendering.

Per questo motivo ogni chiamata setCounter non attiva un singolo rendering. Invece React aggiunge queste funzioni setter in una coda. Li esegue nell'ordine in cui sono stati messi in coda. Gli aggiornamenti apportati allo stato dopo l'esecuzione di tutte le istruzioni si riflettono nel rendering successivo. Questo accodamento di più aggiornamenti di stato è noto come dosaggio. Permette a React di essere più performante.

Pertanto, qui otteniamo un singolo rendering invece di 4 diversi rendering.

Questo esempio è semplice e puoi risolvere questo problema aggiornando il codice come mostrato di seguito:

const handleClick = () => {
setCounter(counter + 4);
    console.log(`%c Counter:${counter}`, "color:green");
    };

Ma cosa succederebbe se avessi un caso d'uso in cui desideri aggiornare lo stato più volte prima del prossimo rendering.

Ecco dove il _ updater _ la funzione è utile.

Possiamo rifattorizzare l'esempio precedente con la funzione di aggiornamento come segue:

const handleClick = () => {
  setCounter(prevCounter => prevCounter + 1);
    setCounter(prevCounter => prevCounter + 1);
    setCounter(prevCounter => prevCounter + 1);
    setCounter(prevCounter => prevCounter + 1);
    console.log(`%c Counter:${counter}`, "color:green");
    };

Qui Contatore precedente ⇒ Contatore precedente + 1 rappresenta la funzione di aggiornamento.

Come spiegato in precedenza, anche queste istruzioni di aggiornamento vengono messe in coda (batching).

La funzione di aggiornamento riceve uno stato in sospeso/precedente che utilizza per calcolare lo stato successivo.

Batch della funzione di aggiornamento

Di seguito è riportato il CodeSandbox con la funzione di aggiornamento aggiunta. Prova a fare clic sul pulsante di incremento.

Funzione di aggiornamento sandbox

Funzione inizializzatore

Dai un'occhiata all'esempio qui sotto. Qui stiamo chiamando la funzione getItems per ottenere il valore iniziale per lo stato.

import React from "react";
import { useState } from "react";
function ListItems() { 
  const getItems = () => { 
    console.log(`%c getItems called`, "color:hotpink");
    	return Array(50).fill(0); 
    }; 
  const [items, setItems] = useState(getItems()); 
    
    return ( 
    	<div className="card">
        <ul> {items.map((item, index) => 
        	( <li key={index}>Item {index + 1}		</li>))} 
        </ul> <button onClick={() => setItems([...items, 0])}>Add Item</button> 	</div> );
} 
export default ListItems;

Questa funzione crea un array con dimensione 50 e riempie l'array con zeri. Fare riferimento all'immagine qui sotto.

Array riempito con 50 zeri

Questi elementi vengono quindi visualizzati sullo schermo.

Sembra tutto a posto ma abbiamo un problema qui.

Clicca sul Aggiungi articolo pulsante (situato dopo l'elenco degli elementi) per aggiungere un nuovo elemento all'elenco. Osserva i registri.

Senza funzione di inizializzatore

Vedi il problema qui?

Il registro "getItems called" viene aggiunto alla console ogni volta che aggiungi un elemento. Ciò significa che questa funzione viene chiamata a ogni rendering.

Ricorda che useState ignora il valore iniziale che gli viene passato dopo il primo rendering, ma qui il valore iniziale viene ancora ricalcolato. Questo può essere costoso se creiamo array di grandi dimensioni o eseguiamo calcoli pesanti.

Possiamo risolvere questo problema passando getItems come _ inizializzatore _ funzione.

Ora, facciamo una piccola modifica al codice.

const [items, setItems] = useState(getItems);

Con funzione inizializzatore

Visualizza la finestra della console in CodeSandbox. Si noti che il registro "getItems called" viene stampato solo al primo rendering. Quando vengono aggiunti elementi successivi, questo registro non è presente.

Anche se non c'è una differenza visiva tra i due esempi, in termini di prestazioni sono diversi.

Ricorda quando hai bisogno di una funzione per lo stato iniziale, passa sempre la funzione o chiama la funzione all'interno di un'altra funzione. Non chiamare mai direttamente la funzione.

✅ const [items, setItems] = useState(getItems);
✅ const [items, setItems] = useState(() => getItems());
❌ const [items, setItems] = useState(getItems());

Quanti hook useState posso avere

Puoi avere tutti gli hook useState all'interno di un componente quanti sono necessari.

Vedi CodeSandbox

Ganci useState multipli

Il componente di seguito ha tre diversi stati: nome utente, password, keepMeSignedIn.

Prova ad aggiornare i valori del nome utente, keepMeSignedIn. Gli stati aggiornati vengono registrati nella console quando si fa clic sul pulsante di accesso.

Highlight

  • useState fornisce un meccanismo per attivare un nuovo rendering e persistere lo stato tra i nuovi rendering.
  • Utilizzare la funzione di aggiornamento quando è necessario:
    • Calcola lo stato successivo in base allo stato precedente.
    • Eseguire più aggiornamenti allo stato prima del rendering successivo.
  • Se lo stato iniziale è ottenuto da una funzione, utilizzare la sintassi della funzione di inizializzazione.
  • Possono esserci più hook useState all'interno di un componente.

Ti è piaciuto questo post? Condividilo con gli altri.
Originariamente scritto per il mio blog personale – https://gauravsen.com/use-state-hook

Timestamp:

Di più da Codementor Reagire Fatto