UseState-kroken - En omfattande guide

UseState-kroken – En omfattande guide

Källnod: 1780723

Vad är en stat?

Innan vi dyker djupt in i useState-kroken låt oss först förstå termen tillstånd.

Tillstånd representerar information om något vid en given tidpunkt.

Låt oss till exempel överväga en textruta.

Inledningsvis finns det ingenting i den här textrutan, så dess tillstånd är det tom. Anta att du börjar skriva Hej i den, för varje tangenttryckning kommer textrutans tillstånd att ändras. Först blir det "H", sedan "He", sedan "Hel" och så vidare tills det blir "Hej".

Observera också att du inte förlorar det tidigare värdet när du skriver. Om du trycker på "H" följt av "e" får du "He" och inte bara "e". Med andra ord kan du tänka på staten som minne i textrutan.

Behovet av stat i en React-komponent.

Låt oss förstå detta med hjälp av ett exempel.

Codesanbox utan stat

Här har vi en ClickCounter komponent som visar hur många gånger man klickade på knappen Öka.

Vi använder en lokal variabel "räknare" för att hålla räkningen på klicken.

Varje gång vi klickar på knappen Öka, handtagKlicka funktionen kommer att anropas. Denna funktion kommer att öka räknarvärdet med 1 och även logga värdet i konsolen.

Fortsätt, klicka på knappen Öka i CodeSandbox-förhandsgranskningen.

Inget hände?

Vår logik verkar vara korrekt. Värdet som loggas i konsolen (CodeSandbox) uppdateras korrekt varje gång vi klickar, men varför återspeglas inte denna uppdatering i användargränssnittet?

Det är på grund av hur React fungerar.

  • Ändringar av lokala variabler utlöser inte en omrendering.
  • Under en omrendering skapas en komponent från grunden, dvs en komponents funktion (i detta exempel är det ClickCounter-funktionen) exekveras igen. Eftersom variabler (till exempel räknare) är lokala för funktionen går deras tidigare värden förlorade.

Så hur får vi komponenten att komma ihåg värden mellan renderingar?

Gif kommer till ett svar

Ja, du fattade rätt! Detta gör vi med hjälp av useState krok.

UseState-kroken

UseState-kroken tillhandahåller mekanismer för att bevara tillståndet och utlösa en omrendering.

Låt oss titta på dess användning.

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

useState-kroken returnerar en array som innehåller två objekt:

  • A tillståndsvariabel som behåller sina värden under omrendering. Det initiala värdet som skickas till useState tilldelas tillståndsvariabeln under den första renderingen.
  • A inställningsfunktion som uppdaterar tillståndsvariabeln och även utlöser en omrendering.
const state = useState(0);
const data = state[0];
const setData = state[1];

Använda array-destrukturering , kan vi refaktorera ovanstående påståenden till ett enda påstående, som visas nedan:

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

Det initiala värdet som skickas till useState används endast under den första renderingen. För omrenderingar ignoreras den.

Räknare med useState

Låt oss nu uppdatera det tidigare räknarexemplet så att det inkluderar useState-kroken.

  • Eftersom vi behöver räknarvärdet mellan återrenderingar, låt oss konvertera det till ett tillstånd.
const [counter, setCounter] = useState(0);
  • Anropar setCounter i handleClick-funktionen.
const handleClick = () => { setCounter(counter + 1); console.log(`%c Counter:${counter}`, "color:green");
};

Funktionen setCounter kommer att uppdatera räknarvärdet med 1 och utlösa en omrendering. När komponentens funktion anropas vid omrendering kommer tillståndsvariabeln som returneras av useState att ha det uppdaterade värdet.

Prova CodeSandbox med den uppdaterade koden. Klicka på knappen Öka och se magin med useState i aktion.

Codesanbox med useState

Du kan verifiera att den funktionella komponenten på en omrendering ClickCounter anropas igen genom att titta på konsolloggarna. Loggen "ClickCounter start" som läggs till i början av komponenten kommer att loggas på varje rendering.

först framför

återge

Uppdateringsfunktion

Anta att vi vill öka värdet på räknaren med 4 för varje klick.

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

Antag att det initiala värdet för räknaren är 0. Vad förväntar du dig att se när du klickar på knappen?

Utan uppdateringsfunktion

Du förväntade dig att siffran skulle vara 4 eller hur? Men varför ser du 1 istället?

a) Varje rendering är associerad med ett tillstånd. Värdet på det tillståndet förblir låst under renderingens livstid.

Observera att loggen inuti handleClick-funktionen skriver ut räknarvärdet som 0.

Oavsett hur många gånger du anropar setCounter-metoden förblir värdet på räknaren detsamma.

const handleClick = () => { setCounter(counter + 1); setCounter(counter + 1); setCounter(counter + 1); setCounter(counter + 1); console.log(`%c Counter:${counter}`, "color:green"); };
b) Förrän all kod i en händelsehanterare exekveras, kommer React inte att utlösa en omrendering.

Av denna anledning utlöser inte varje setCounter-anrop en individuell rendering. Istället lägger React till dessa sätterfunktioner i en kö. Avrättar dem i den ordning de var i kö. De uppdateringar som gjorts av tillståndet efter att alla uttalanden har körts återspeglas i nästa rendering. Denna kö av flera tillståndsuppdateringar kallas dosering. Det gör att React kan bli mer presterande.

Därför får vi här en enda rendering istället för 4 olika renderingar.

Det här exemplet är enkelt och du kan åtgärda det här problemet genom att uppdatera koden enligt nedan:

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

Men tänk om du hade ett användningsfall där du ville uppdatera tillståndet flera gånger innan nästa rendering.

Det är där _ uppdaterare _-funktionen kommer till hands.

Vi kan refaktorera det föregående exemplet med uppdateringsfunktionen enligt följande:

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

Här prevCounter ⇒ prevCounter + 1 representerar uppdateringsfunktionen.

Som förklarats tidigare är dessa uppdateringssatser också i kö (batchning).

Uppdateringsfunktionen tar emot ett väntande/föregående tillstånd som den använder för att beräkna nästa tillstånd.

Batchning av uppdateringsfunktioner

Nedan finns CodeSandbox med uppdateringsfunktionen tillagd. Försök att klicka på inkrementknappen.

Uppdateringsfunktion sandlåda

Initialiseringsfunktion

Ta en titt på exemplet nedan. Här anropar vi getItems-funktionen för att få initialvärdet för 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;

Denna funktion skapar en array med storlek 50 och fyller arrayen med nollor. Se bilden nedan.

Array fylld med 50 nollor

Dessa objekt visas sedan på skärmen.

Allt verkar vara bra men vi har ett problem här.

Klicka på Lägg till artikel knappen (finns efter listan med objekt) för att lägga till ett nytt objekt i listan. Observera loggarna.

Utan initialiseringsfunktion

Ser du problemet här?

Loggen "getItems called" läggs till i konsolen varje gång du lägger till ett objekt. Detta betyder att denna funktion anropas vid varje rendering.

Kom ihåg att useState ignorerar det initiala värdet som skickas till det efter den första renderingen, men här räknas fortfarande om det initiala värdet. Detta kan bli dyrt om vi skapar stora arrayer eller utför tunga beräkningar.

Vi kan lösa det här problemet genom att passera getItems som en _ initialiserare _ funktion.

Låt oss nu göra en liten ändring i koden.

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

Med initialiseringsfunktion

Se konsolfönstret i CodeSandbox. Observera att "getItems called"-loggen endast skrivs ut vid den första renderingen. När efterföljande objekt läggs till finns inte denna logg där.

Även om det inte finns någon visuell skillnad mellan de två exemplen, är de olika när det gäller prestanda.

Kom ihåg att när du behöver en funktion för initialtillståndet, skicka alltid funktionen eller anropa funktionen i en annan funktion. Ring aldrig funktionen direkt.

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

Hur många useState-krokar kan jag ha

Du kan ha så många useState-krokar inuti en komponent som den kräver.

Se CodeSandbox

Multiple useState krokar

Komponenten nedan har tre olika tillstånd – användarnamn, lösenord, keepMeSignedIn.

Prova att uppdatera värdena för användarnamn, keepMeSignedIn. De uppdaterade tillstånden loggas i konsolen när inloggningsknappen klickas.

Höjdpunkter

  • useState tillhandahåller en mekanism för att utlösa en omrendering och bevara tillståndet mellan omrenderingar.
  • Använd uppdateringsfunktionen när du behöver:
    • Beräkna nästa tillstånd baserat på föregående tillstånd.
    • Utför flera uppdateringar av tillståndet innan nästa rendering.
  • Om initialtillstånd erhålls från en funktion – använd syntaxen för initialiseringsfunktionen.
  • Det kan finnas flera useState-krokar inuti en komponent.

Gillade du det här inlägget? Dela det med andra.
Ursprungligen skriven för min personliga blogg - https://gauravsen.com/use-state-hook

Tidsstämpel:

Mer från Codementor React Fakta