Er det overhovedet muligt at opdatere objekt's egenskaber med setState?
Noget i stil med:
this.state = {
jasper: { name: 'jasper', age: 28 },
}
Jeg har prøvet:
this.setState({jasper.name: 'someOtherName'});
og dette:
this.setState({jasper: {name: 'someothername'}})
Den første resulterer i en syntaksfejl, og den anden gør bare ingenting. Nogen ideer?
Der er flere måder at gøre dette på, da state update er en asynkron operation, så for at opdatere state-objektet skal vi bruge updater-funktionen med setState
.
1- Den enkleste:
Først oprettes en kopi af jasper
og derefter foretages ændringerne i den:
this.setState(prevState => {
let jasper = Object.assign({}, prevState.jasper); // creating copy of state variable jasper
jasper.name = 'someothername'; // update the name property, assign a new value
return { jasper }; // return new object jasper object
})
I stedet for at bruge Object.assign
kan vi også skrive det sådan her:
let jasper = { ...prevState.jasper };
2- Brug af [spredningsoperator]3:
this.setState(prevState => ({
jasper: { // object that we want to update
...prevState.jasper, // keep all other key-value pairs
name: 'something' // update the value of specific key
}
}))
Bemærk: Object.assign
og Spread Operator
skaber kun shallow copy, så hvis du har defineret et indlejret objekt eller array af objekter, har du brug for en anden fremgangsmåde.
Antag, at du har defineret state som:
this.state = {
food: {
sandwich: {
capsicum: true,
crackers: true,
mayonnaise: true
},
pizza: {
jalapeno: true,
extraCheese: false
}
}
}
Sådan opdaterer du ekstraCheese i pizza-objektet:
this.setState(prevState => ({
food: {
...prevState.food, // copy all other key-value pairs of food object
pizza: { // specific object of food object
...prevState.food.pizza, // copy all pizza key-value pairs
extraCheese: true // update value of specific key
}
}
}))
Lad os antage, at du har en todo app, og du administrerer dataene i denne formular:
this.state = {
todoItems: [
{
name: 'Learn React Basics',
status: 'pending'
}, {
name: 'Check Codebase',
status: 'pending'
}
]
}
For at opdatere status for et todo objekt, skal du køre et map på arrayet og kontrollere for en unik værdi for hvert objekt, i tilfælde af condition=true
, returnerer du det nye objekt med opdateret værdi, ellers samme objekt.
let key = 2;
this.setState(prevState => ({
todoItems: prevState.todoItems.map(
el => el.key === key? { ...el, status: 'done' }: el
)
}))
Suggestion: Hvis objektet ikke har en unik værdi, skal du bruge array-indeks.
I det første tilfælde er der faktisk tale om en syntaksfejl.
Da jeg ikke kan se resten af din komponent, er det svært at se, hvorfor du indlejrer objekter i din tilstand her. Det er ikke en god idé at indlejre objekter i komponenttilstand. Prøv at indstille din oprindelige tilstand til at være:
this.state = {
name: 'jasper',
age: 28
}
På den måde kan du bare kalde, hvis du ønsker at opdatere navnet:
this.setState({
name: 'Sean'
});
Vil det opnå det, som du ønsker?
Til større, mere komplekse datalagre ville jeg bruge noget som Redux. Men det'er meget mere avanceret.
Den generelle regel med komponenttilstand er kun at bruge den til at administrere komponentens UI-tilstand (f.eks. aktiv, timere osv.)
Tjek disse referencer ud:
En anden mulighed er at definere variablen ud fra Jasper-objektet og derefter bare kalde en variabel.
Spread operator: ES6
this.state = { jasper: { name: 'jasper', age: 28 } }
let foo = "something that needs to be saved into state"
this.setState(prevState => ({
jasper: {
...jasper.entity,
foo
}
})