UseState hook - En omfattende guide PlatoBlockchain Data Intelligence. Lodret søgning. Ai.

UseState-krogen – En omfattende guide

Hvad er en stat?

Før vi dykker dybt ned i useState-krogen, lad os først forstå udtrykket tilstand.

Tilstand repræsenterer information om noget på et givet tidspunkt.

Lad os for eksempel overveje en tekstboks.

Til at begynde med er der intet i denne tekstboks, så dens tilstand er det tom. Antag, at du begynder at skrive Hej inde i den, for hvert tastetryk ændres tekstboksens tilstand. Først vil det være "H", så "Han", så "Hel" og så videre, indtil det bliver "Hej".

Bemærk også, at mens du skriver, mister du ikke den tidligere værdi. Hvis du trykker på "H" efterfulgt af "e", får du "Han" og ikke kun "e". Med andre ord kan du tænke på staten som hukommelse af tekstboksen.

Behovet for tilstand i en React-komponent.

Lad os forstå dette ved hjælp af et eksempel.

Codesanbox uden stat

Her har vi en Kliktæller komponent, som viser antallet af gange, der blev klikket på knappen Inkrement.

Vi bruger en lokal variabel "tæller" for at holde optællingen af ​​klikkene.

Hver gang vi klikker på knappen Forøg, håndtag Klik funktion vil blive aktiveret. Denne funktion vil øge tællerværdien med 1 og også logge værdien i konsollen.

Gå videre, klik på Forøg knappen i CodeSandbox preview.

Intet skete?

Vores logik ser ud til at være korrekt. Værdien logget i konsollen (CodeSandbox) opdateres korrekt, hver gang vi klikker, men hvorfor afspejles denne opdatering ikke i brugergrænsefladen?

Det er på grund af den måde, React fungerer på.

  • Ændringer i lokale variabler udløser ikke en gengivelse.
  • Under en re-rendering oprettes en komponent fra bunden, dvs. en komponents funktion (i dette eksempel er det ClickCounter-funktionen) udføres igen. Da variabler (for eksempel tæller) er lokale for funktionen, går deres tidligere værdier tabt.

Så hvordan får vi komponenten til at huske værdier mellem gengivelser?

Ja, du har ret! Det gør vi ved hjælp af useState krog.

UseState-krogen

UseState-krogen giver mekanismer til at bevare tilstanden og udløse en gengivelse.

Lad os se på dens brug.

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

// OR

const state = React.useState(initialValue);

useState-krogen returnerer et array, som indeholder to elementer:

  • A tilstandsvariabel der bevarer sine værdier under gengivelser. Den initiale værdi, der sendes til useState, tildeles tilstandsvariablen under den første gengivelse.
  • A sætter funktion der opdaterer tilstandsvariablen og udløser også en gengivelse.
const state = useState(0);
const data = state[0];
const setData = state[1];

Ved brug af array-destrukturering , kan vi refaktorisere ovenstående udsagn til en enkelt udsagn, som vist nedenfor:

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

Den initiale værdi, der sendes til useState, bruges kun under den første gengivelse. For gengivelser ignoreres den.

Tæller med useState

Lad os nu opdatere det tidligere tællereksempel til at inkludere useState-krogen.

  • Da vi har brug for tællerværdien mellem gengivelser, lad os konvertere den til en tilstand.
const [counter, setCounter] = useState(0);
  • Kalder setCounter inde i handleClick-funktionen.
const handleClick = () => {
  setCounter(counter + 1);
  console.log(`%c Counter:${counter}`, "color:green");
};

SetCounter-funktionen vil opdatere tællerværdien med 1 og udløse en gengivelse. Når komponentens funktion kaldes på genrender, vil tilstandsvariablen returneret af useState have den opdaterede værdi.

Prøv CodeSandbox med den opdaterede kode. Klik på knappen Inkrement og se magien ved useState i aktion.

Codesanbox med useState

Du kan bekræfte, at den funktionelle komponent ved en gengivelse Kliktæller kaldes igen ved at se konsollogfilerne. Loggen "ClickCounter start", som tilføjes i begyndelsen af ​​komponenten, vil blive logget på hver gengivelse.

første gengivelse

gengive

Opdateringsfunktion

Antag, at vi ønsker at øge værdien af ​​tæller med 4 for hvert klik.

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

Antag, at startværdien af ​​tælleren er 0. Hvad forventer du at se, når du klikker på knappen?

Uden opdateringsfunktion

Du forventede, at antallet ville være 4, ikke? Men hvorfor ser du 1 i stedet for?

a) Hver gengivelse er forbundet med en tilstand. Værdien af ​​denne tilstand forbliver låst i hele denne gengivelses levetid.

Bemærk, at loggen inde i handleClick-funktionen udskriver tællerværdien som 0.

Uanset hvor mange gange du kalder setCounter-metoden, forbliver værdien af ​​tælleren den samme.

const handleClick = () => {
  setCounter(counter + 1);
    setCounter(counter + 1);
    setCounter(counter + 1);
    setCounter(counter + 1);
    console.log(`%c Counter:${counter}`, "color:green");
    };
b) Indtil al koden inde i en hændelseshandler er eksekveret, vil React ikke udløse en gengivelse.

Af denne grund udløser hvert setCounter-kald ikke en individuel gengivelse. I stedet tilføjer React disse indstillingsfunktioner i en kø. Eksekverer dem i den rækkefølge, de var i kø. De opdateringer, der er foretaget til staten efter at have udført alle sætningerne, afspejles i den næste gengivelse. Denne kø af flere tilstandsopdateringer er kendt som vejeafmålings. Det giver React mulighed for at være mere performant.

Derfor får vi her en enkelt render i stedet for 4 forskellige renders.

Dette eksempel er enkelt, og du kan løse dette problem ved at opdatere koden som vist nedenfor:

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

Men hvad nu hvis du havde en use case, hvor du ville opdatere tilstanden flere gange før den næste gengivelse.

Det er her _ updater _ funktion kommer praktisk.

Vi kan refaktorere det foregående eksempel med opdateringsfunktionen som følger:

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");
    };

Her prevCounter ⇒ prevCounter + 1 repræsenterer opdateringsfunktionen.

Som forklaret tidligere er disse opdateringssætninger også i kø (batching).

Opdateringsfunktionen modtager en afventende/forrige tilstand, som den bruger til at beregne den næste tilstand.

Opdateringsfunktion batching

Nedenfor er CodeSandbox med opdateringsfunktionen tilføjet. Prøv at klikke på stigningsknappen.

Updater funktion sandkasse

Initialiseringsfunktion

Tag et kig på eksemplet nedenfor. Her kalder vi getItems-funktionen for at få startværdien for staten.

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;

Denne funktion opretter et array med størrelse 50 og fylder arrayet med nuller. Se billedet nedenfor.

Array fyldt med 50 nuller

Disse elementer vises derefter på skærmen.

Alt ser ud til at være i orden, men vi har et problem her.

Klik på Tilføj produkt knap (placeret efter listen over elementer) for at tilføje et nyt element til listen. Overhold logfilerne.

Uden initialiseringsfunktion

Ser du problemet her?

Loggen "getItems called" bliver tilføjet til konsollen, hver gang du tilføjer et element. Det betyder, at denne funktion kaldes på hver gengivelse.

Husk, at useState ignorerer den initiale værdi, der sendes til den efter den første gengivelse, men her bliver den initiale værdi stadig genberegnet. Dette kan være dyrt, hvis vi opretter store arrays eller udfører tunge beregninger.

Vi kan løse dette problem ved at bestå getItems som en _ initialisering _ funktion.

Lad os nu lave en lille ændring af koden.

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

Med initialiseringsfunktion

Se konsolvinduet i CodeSandbox. Bemærk, at "getItems Called"-log kun udskrives ved den første gengivelse. Når efterfølgende elementer tilføjes, er denne log der ikke.

Selvom der ikke er en visuel forskel mellem de to eksempler, er de forskellige med hensyn til ydeevne.

Husk, når du har brug for en funktion til den oprindelige tilstand, skal du altid videregive funktionen eller kalde funktionen inde i en anden funktion. Kald aldrig funktionen direkte.

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

Hvor mange useState kroge kan jeg have

Du kan have så mange useState-kroge inde i en komponent, som det kræver.

Se CodeSandbox

Multiple useState kroge

Komponenten nedenfor har tre forskellige tilstande - brugernavn, adgangskode, keepMeSignedIn.

Prøv at opdatere værdierne for brugernavn, keepMeSignedIn. De opdaterede tilstande logges i konsollen, når der klikkes på login-knappen.

Highlights

  • useState giver en mekanisme til at udløse en gengivelse og opretholde tilstanden mellem gengivelserne.
  • Brug opdateringsfunktionen, når du har brug for at:
    • Beregn den næste tilstand baseret på den forrige tilstand.
    • Udfør flere opdateringer til tilstanden før næste gengivelse.
  • Hvis starttilstanden opnås fra en funktion – brug initialiseringsfunktionens syntaks.
  • Der kan være flere useState-hooks inde i en komponent.

Kan du lide dette indlæg? Del det med andre.
Oprindeligt skrevet til min personlige blog - https://gauravsen.com/use-state-hook

Tidsstempel:

Mere fra Kodementor-reaktionsfakta