Förstå React ’setState’
React-komponenter kan, och ofta, ha tillstånd. Staten kan vara vad som helst, men tänk på saker som om en användare är inloggad eller inte och visar rätt användarnamn baserat på vilket konto som är aktivt. Eller en rad blogginlägg. Eller om en modal är öppen eller inte och vilken flik i den är aktiv.
React-komponenter med state render UI baserat på det tillståndet. När tillståndet för komponenter ändras, så gör komponentgränssnittet.
som gör det viktigt att förstå när och hur du ändrar tillståndet för din komponent. I slutet av denna handledning bör du veta hur setState
fungerar och kunna undvika vanliga fallgropar som många av oss träffar när när vi lär oss reagera.
arbetet med ’setState ()’
setState()
är det enda legitima sättet att uppdatera tillståndet efter den ursprungliga tillståndsinställningen. Låt oss säga att vi har en sökkomponent och vill visa söktermen som en användare skickar in.
här är inställningen:
import React, { Component } from 'react'class Search extends Component { constructor(props) { super(props) state = { searchTerm: '' } }}
Vi skickar en tom sträng som ett värde och för att uppdatera tillståndet för searchTerm
måste vi ringa setState()
.
setState({ searchTerm: event.target.value })
här skickar vi ett objekt till setState()
. Objektet innehåller den del av staten vi vill uppdatera, vilket i detta fall är värdet på searchTerm
. React tar detta värde och slår samman det i objektet som behöver det. Det är ungefär som Search
komponenten frågar vad den ska använda för värdet av searchTerm
och setState()
svarar med ett svar.
detta är i grunden sparka igång en process som reagerar samtal avstämning. Avstämningsprocessen är hur React uppdaterar DOM, genom att göra ändringar i komponenten baserat på tillståndsförändringen. När begäran till setState()
utlöses skapar React ett nytt träd som innehåller de reaktiva elementen i komponenten (tillsammans med det uppdaterade tillståndet). Detta träd används för att räkna ut hur Search
komponentens användargränssnitt ska ändras som svar på tillståndsändringen genom att jämföra den med elementen i föregående träd. React vet vilka ändringar som ska implementeras och uppdaterar endast de delar av DOM där det behövs. Det är därför React är snabbt.
det låter som mycket, men för att sammanfatta flödet:
- Vi har en sökkomponent som visar en sökterm
- den söktermen är för närvarande Tom
- användaren skickar in en sökterm
- den termen fångas och lagras av
setState
som ett värde - avstämning sker och React märker att värdeförändringen
- React instruerar sökkomponenten att uppdatera värdet och söktermen sparas sammanfogas i
avstämningsprocessen ändrar inte nödvändigtvis hela trädet, utom i en situation där trädets rot ändras så här:
// old<div> <Search /></div>// new<span> <Search /></span>
alla <div>
taggar blir <span>
taggar och hela komponentträdet kommer att uppdateras som ett resultat.
tumregeln är att aldrig mutera staten direkt. Använd alltid setState()
för att ändra tillstånd. Att ändra tillståndet direkt, som utdraget nedan, kommer inte att orsaka att komponenten återges.
// do not do thisthis.state = { searchTerm: event.target.value}
överför en funktion till `setState()`
för att visa den här tanken ytterligare, låt oss skapa en enkel räknare som ökar och minskar på klick.
se pennan setState penna av Kingsley Silas Chijioke (@kinsomicrote) på CodePen.
låt oss registrera komponenten och definiera markeringen för användargränssnittet:
class App extends React.Component {state = { count: 0 }handleIncrement = () => { this.setState({ count: this.state.count + 1 })}handleDecrement = () => { this.setState({ count: this.state.count - 1 })} render() { return ( <div> <div> {this.state.count} </div> <button onClick={this.handleIncrement}>Increment by 1</button> <button onClick={this.handleDecrement}>Decrement by 1</button> </div> ) }}
vid denna tidpunkt ökar eller minskar räknaren helt enkelt räkningen med 1 på varje klick.
men vad händer om vi ville öka eller minska med 3 istället? Vi kan försöka ringa setState()
tre gånger i funktionernahandleDecrement
ochhandleIncrement
så här:
handleIncrement = () => { this.setState({ count: this.state.count + 1 }) this.setState({ count: this.state.count + 1 }) this.setState({ count: this.state.count + 1 })}handleDecrement = () => { this.setState({ count: this.state.count - 1 }) this.setState({ count: this.state.count - 1 }) this.setState({ count: this.state.count - 1 })}
om du kodar hemma kan du bli förvånad över att det inte fungerar.
ovanstående kodavsnitt motsvarar:
Object.assign( {}, { count: this.state.count + 1 }, { count: this.state.count + 1 }, { count: this.state.count + 1 },)
Object.assign()
används för att kopiera data från ett källobjekt till ett målobjekt. Om data som kopieras från källan till målet alla har samma nycklar, som i vårt exempel, vinner det sista objektet. Här är en enklare version av hur Object.assign()
fungerar;
let count = 3const object = Object.assign({}, {count: count + 1}, {count: count + 2}, {count: count + 3});console.log(object);// output: Object { count: 6 }
så istället för att samtalet händer tre gånger händer det bara en gång. Detta kan åtgärdas genom att skicka en funktion till setState()
. Precis som du skickar objekt till setState()
, kan du också skicka funktioner, och det är vägen ut ur situationen ovan.
om vi redigerar funktionen handleIncrement
för att se ut så här:
handleIncrement = () => { this.setState((prevState) => ({ count: prevState.count + 1 })) this.setState((prevState) => ({ count: prevState.count + 1 })) this.setState((prevState) => ({ count: prevState.count + 1 }))}
…Vi kan nu öka antalet tre gånger med ett klick.
i det här fallet, istället för att slå samman, reagerar köerna funktionen anropar i den ordning de görs och uppdaterar hela tillståndet det är gjort. Detta uppdaterar tillståndet för räkningen till 3 istället för 1.
öppna tidigare tillstånd med Updater
När du bygger React-applikationer finns det tillfällen då du vill beräkna tillstånd baserat på komponentens tidigare tillstånd. Du kan inte alltid lita på this.state
för att hålla rätt tillstånd omedelbart efter att du har ringt setState()
, eftersom det alltid är lika med det tillstånd som återges på skärmen.
Låt oss gå tillbaka till vårt räknarexempel för att se hur detta fungerar. Låt oss säga att vi har en funktion som minskar vår räkning med 1. Denna funktion ser ut så här:
changeCount = () => { this.setState({ count: this.state.count - 1})}
vad vi vill ha är förmågan att minska med 3. Funktionen changeCount()
kallas tre gånger i en funktion som hanterar klickhändelsen, så här.
handleDecrement = () => { this.changeCount() this.changeCount() this.changeCount()}
varje gång du klickar på knappen för att minska, kommer räkningen att minska med 1 istället för 3. Detta beror på attthis.state.count
inte uppdateras förrän komponenten har återrenderats. Lösningen är att använda en uppdaterare. En uppdaterare låter dig komma åt det aktuella läget och använda det omedelbart för att uppdatera andra objekt. Så funktionen changeCount()
kommer att se ut så här.
changeCount = () => { this.setState((prevState) => { return { count: prevState.count - 1} })}
Nu är vi inte beroende av resultatet av this.state
. Tillstånden för count
är byggda på varandra så att vi kan komma åt rätt tillstånd som ändras med varje samtal till changeCount()
.
setState()
ska behandlas asynkront — med andra ord, förvänta dig inte alltid att staten har ändrats efter att ha ringt setState()
.
inslagning upp
När du arbetar med setState()
, dessa är de viktigaste sakerna du bör veta:
- uppdatering till en komponent tillstånd bör göras med
setState()
- Du kan skicka ett objekt eller en funktion till
setState()
- skicka en funktion när du kan uppdatera tillstånd flera gånger
- beror inte på detta.ange omedelbart efter Anropet
setState()
och använd uppdateringsfunktionen istället.