是否可以使用setstate
更新对象的属性?
类似于:
this.state = {
jasper: { name: 'jasper', age: 28 },
}
我试过:
this.setState({jasper.name: 'someOtherName'});
还有这个:
this.setState({jasper: {name: 'someothername'}})
第一个会导致语法错误,而第二个则什么也不做。有什么想法吗?
有多种方法可以这样做,因为状态更新是一个异步操作,所以要更新状态对象,我们需要使用带有setstate
的updater函数。
1-最简单的一个:
首先创建jasper
的副本,然后在其中进行更改:
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
})
与其使用object.assign
,我们还可以这样编写它:
let jasper = { ...prevState.jasper };
2-使用扩展语法:
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
}
}))
注意:object.assign
和spread operator
只创建浅层副本,因此如果定义了嵌套对象或对象数组,则需要另一种方法。
假设您已将state定义为:
this.state = {
food: {
sandwich: {
capsicum: true,
crackers: true,
mayonnaise: true
},
pizza: {
jalapeno: true,
extraCheese: false
}
}
}
更新pizza对象的extraCheese:
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
}
}
}))
假设您有一个todo应用程序,并且您正在管理以下表单中的数据:
this.state = {
todoItems: [
{
name: 'Learn React Basics',
status: 'pending'
}, {
name: 'Check Codebase',
status: 'pending'
}
]
}
若要更新任何todo对象的状态,请在数组上运行映射并检查每个对象的某个唯一值,如果condition=true
,则返回具有更新值的新对象,否则返回相同的对象。
let key = 2;
this.setState(prevState => ({
todoItems: prevState.todoItems.map(
el => el.key === key? { ...el, status: 'done' }: el
)
}))
建议:如果对象没有唯一的值,那么使用数组索引。
这是最快也是最易读的方式:
this.setState({...this.state.jasper, name: 'someothername'});
即使this.state.jasper
已经包含name属性,也会使用新名称name:'someotherName'
with。