所以这就是我的状态:
this.state = {
ids: ['A', 'E', 'C']
};
如何修改状态,以便将索引1处的'E'更改为'B'呢?例如:
this.setState({
ids[1]: 'B'
});
如何完成这个任务?
所以这就是我的状态:
this.state = {
ids: ['A', 'E', 'C']
};
如何修改状态,以便将索引1处的'E'更改为'B'呢?例如:
this.setState({
ids[1]: 'B'
});
如何完成这个任务?
我的建议是逐渐习惯使用不可变操作,这样您就不会修改内部状态对象。
正如在React文档中所指出的:
永远不要直接改变 this.state 的值,因为调用 setState() 之后可能会替换您所做的更改。将 this.state 视为不可变。
在这种情况下,您可以[1]使用slice()
获取数组的新副本,[2]对副本进行操作,然后[3]使用新的数组调用setState。这是一个好习惯。
就像这样:
const newIds = this.state.ids.slice() //copy the array
newIds[1] = 'B' //execute the manipulations
this.setState({ids: newIds}) //set the new state
this.state.a='a'
,不要直接更改任何状态变量的值。把 this.state
当作不可变的对象来处理,始终使用 setState
来更改状态值。如果我理解有误,请纠正我。 - Mayank Shuklathis.state
修改相同的数组/对象将改变相同的内部对象。 - mrlewslice()
制作该副本,它才看到状态更改。 - Dave情况1:如果您知道索引,则可以这样写:
let ids = [...this.state.ids]; // create the copy of state array
ids[index] = 'k'; //new value
this.setState({ ids }); //update the value
第二种情况:如果您不知道索引,则首先使用array.findIndex或者任何其他循环来获取要更新的项的索引,然后更新该值并使用setState。
像这样:
let ids = [...this.state.ids];
let index = ids.findIndex(el => /* condition */);
ids[index] = 'k';
this.setState({ ids });
这里有另一种解决方案可以在setState中更改特定索引的数组:
this.setState({
...array,
Object.assign([...array], { [id]: yourNewObjectOrValue })
})
在@mayank-shukla所写的基础上(情况2:知道要替换的项的索引),也可以使用Array.splice来编写:
const replacement = 'B';
let copy = [...this.state.ids]
copy.splice(index, 1, replacement)
this.setState({
ids: copy,
})
这里有两件事需要注意:
Array.splice
是可变的;它会更改它操作的数组,但由于展开运算符,这是一个浅拷贝的数组。请参见下面的更多信息。Array.splice
的返回值实际上是删除的元素。即:不要将切片结果分配给您打算分配给 setState
中的 IDs 变量,否则您最终只会得到已删除的值。关于第一点中的浅复制和深复制,请注意,如果您正在替换对象引用(而不是问题中的字符串文本),则需要使用类似于 lodash 的 cloneDeep。
还有其他一些 解决方法。
您还可以在 SO 上 阅读更多关于浅复制和深复制的内容。
this.setState({
ids: [ids[1]='B',...ids].slice(1)
});
this.setState({
ids: [ids.splice(1,1,'B')]
})
this.setState
,您可以使用它来转换状态。this.setState(state => produce(state, state => {
state.ids[1] = 'b'
}));
或者,如果你更喜欢柯里化,produce(fn)
是一个有用的快捷方式,可以创建一个函数,接受一个参数并将其转发到你的变换中:
this.setState(produce(state => {
state.ids[1] = 'b'
}));
我发现当涉及到深层状态更改时,Immer非常好用,但请注意它并非免费。