本文翻译自:Correct modification of state arrays in ReactJS
I want to add an element to the end of a state
array, is this the correct way to do it? 我想在state
数组的末尾添加一个元素,这是正确的方法吗?
this.state.arrayvar.push(newelement);
this.setState({arrayvar:this.state.arrayvar});
I am concerned that modifying the array in-place with push
might cause trouble - is it safe? 我担心通过push
就地修改数组可能会引起麻烦-是否安全?
The alternative of making a copy of the array, and setState
ing that seems wasteful. 复制数组和setState
替代方法似乎很浪费。
#1楼
参考:https://stackoom.com/question/1m9h9/在ReactJS中正确修改状态数组
#2楼
The React docs says: React文档说:
Treat this.state as if it were immutable. 将this.state视为不可变的。
Your push
will mutate the state directly and that could potentially lead to error prone code, even if you are "resetting" the state again afterwards. 您的push
将直接改变状态,即使您此后再次“重置”状态,也有可能导致易于出错的代码。 F.ex, it could lead to that some lifecycle methods like componentDidUpdate
won't trigger. 例如,它可能导致某些生命周期方法(例如componentDidUpdate
不会触发。
The recommended approach in later React versions is to use an updater function when modifying states to prevent race conditions: 在更高版本的React中,建议的方法是在修改状态以防止竞争情况时使用updater函数:
this.setState(prevState => ({
arrayvar: [...prevState.arrayvar, newelement]
}))
The memory "waste" is not an issue compared to the errors you might face using non-standard state modifications. 与使用非标准状态修改可能会遇到的错误相比,内存“浪费”不是问题。
Alternative syntax for earlier React versions 早期React版本的替代语法
You can use concat
to get a clean syntax since it returns a new array: 您可以使用concat
获得干净的语法,因为它返回一个新数组:
this.setState({
arrayvar: this.state.arrayvar.concat([newelement])
})
In ES6 you can use the Spread Operator : 在ES6中,您可以使用Spread运算符 :
this.setState({
arrayvar: [...this.state.arrayvar, newelement]
})
#3楼
As @nilgun mentioned in the comment, you can use the react immutability helpers . 如评论中提到的@nilgun,您可以使用react 不可变性助手 。 I've found this to be super useful. 我发现这非常有用。
From the docs: 从文档:
Simple push 简单推
var initialArray = [1, 2, 3];
var newArray = update(initialArray, {$push: [4]}); // => [1, 2, 3, 4]
initialArray is still [1, 2, 3]. initialArray仍为[1、2、3]。
#4楼
Easiest, if you are using ES6
. 如果您使用的是ES6
,则最简单。
initialArray = [1, 2, 3];
newArray = [ ...initialArray, 4 ]; // --> [1,2,3,4]
New array will be [1,2,3,4]
新数组将为[1,2,3,4]
to update your state in React 在React中更新您的状态
this.setState({
arrayvar:[...this.state.arrayvar, newelement]
});
Learn more about array destructuring 了解有关数组解构的更多信息
#5楼
React may batch updates, and therefore the correct approach is to provide setState with a function that performs the update. React可能会批量更新,因此正确的方法是为setState提供执行更新的功能。
For the React update addon, the following will reliably work: 对于React更新插件,以下将可靠地工作:
this.setState( state => update(state, {array: {$push: [4]}}) );
or for concat(): 或对于concat():
this.setState( state => ({
array: state.array.concat([4])
}));
The following shows what https://jsbin.com/mofekakuqi/7/edit?js,output as an example of what happens if you get it wrong. 下面显示了https://jsbin.com/mofekakuqi/7/edit?js的输出,作为输出示例,说明如果弄错了怎么办。
The setTimeout() invocation correctly adds three items because React will not batch updates within a setTimeout callback (see https://groups.google.com/d/msg/reactjs/G6pljvpTGX0/0ihYw2zK9dEJ ). setTimeout()调用正确添加了三个项目,因为React不会在setTimeout回调中批量更新(请参阅https://groups.google.com/d/msg/reactjs/G6pljvpTGX0/0ihYw2zK9dEJ )。
The buggy onClick will only add "Third", but the fixed one, will add F, S and T as expected. 越野车onClick仅会添加“第三”,而固定的onClick将按预期添加F,S和T。
class List extends React.Component {
constructor(props) {
super(props);
this.state = {
array: []
}
setTimeout(this.addSome, 500);
}
addSome = () => {
this.setState(
update(this.state, {array: {$push: ["First"]}}));
this.setState(
update(this.state, {array: {$push: ["Second"]}}));
this.setState(
update(this.state, {array: {$push: ["Third"]}}));
};
addSomeFixed = () => {
this.setState( state =>
update(state, {array: {$push: ["F"]}}));
this.setState( state =>
update(state, {array: {$push: ["S"]}}));
this.setState( state =>
update(state, {array: {$push: ["T"]}}));
};
render() {
const list = this.state.array.map((item, i) => {
return <li key={i}>{item}</li>
});
console.log(this.state);
return (
<div className='list'>
<button onClick={this.addSome}>add three</button>
<button onClick={this.addSomeFixed}>add three (fixed)</button>
<ul>
{list}
</ul>
</div>
);
}
};
ReactDOM.render(<List />, document.getElementById('app'));
#6楼
The simplest way with ES6
: ES6
最简单的方法:
this.setState(prevState => ({
array: [...prevState.array, newElement]
}))