请这不是重复的问题。我的问题是,如果将状态数组分配给局部变量并将值推入局部变量,是否会引起错误。
我陷入困境,了解将值推入React状态数组或覆盖值时哪个是正确的。
根据React文档,以下代码风格不好,并会导致错误
this.state = {
list: []
}
componentDidMount(){
const { list } = this.state;
list.push(“test”);//this is bad style of pushing values into React state and causes a bug
this.setState({list});
}
如果我在下面这样做,会导致错误吗?将状态列表分配给局部变量,并将值推入该局部变量,并将数组的状态设置为list。这和上面的代码一样吗?
this.state = {
list: []
}
componentDidMount(){
const { list } = this.state;
const array = list;
array.push(“test”); //pushing values to a local variable too a bad style and causes a bug in React?
this.setState({list: array});
}
答案 0 :(得分:4)
是的,您的第二种方法也会导致错误,因为状态数组在此阶段被更新{array.push(“ test”); }。而且,如果您的类是PureComponent,那么它将不会重新渲染。
所以你可以尝试
const list = [... this.state.list];
OR
const list = this.state.list.slice();
以这种方式创建数组的副本。
您的新代码如下所示:-
const list = [... this.state.list];
list.push("new value");
this.setState({ list });
答案 1 :(得分:3)
您的第一个示例实际上并不是React错误,我不确定它完全可以视为Bug。 Array.prototype.push()
改变了数组,这是您要在React中避免的事情(不要直接修改状态)。
很显然,您可以使用Array.prototype.slice()
let newList = this.state.list.slice();
newList.push(someValue);
this.setState({ list: newList })
另一种选择是简单地在您的Array.prototype.concat()
中使用setState()
方向
this.setState({ list: this.state.list.concat(someValue)})
我想这是我现在想到的选择。
答案 2 :(得分:3)
这不是错误,而是预期的行为。状态不应该被改变。
问题中的两个代码段是相同的,数组是对象,并且对象是通过JavaScript引用传递的,因此无论是list
还是array
被突变。
list
数组应该是不可变的,即,如果需要对其进行更改,则会创建一个新的数组。
此外,在this.state
中使用this.setState
的值是antipattern:
setState()并不总是立即更新组件。它可能会批量更新或将更新推迟到以后。这使得在调用setState()之后立即读取this.state可能是一个陷阱。而是使用componentDidUpdate或setState回调(setState(updater,callback)),确保在应用更新后均能触发这两种方法。如果需要基于先前的状态来设置状态,请阅读以下有关updater参数的信息。
应使用更新程序功能:
componentDidMount(){
this.setState(({ list }) => ({ list: [...list, 'test'] }));
}
答案 3 :(得分:2)
this.setState({ list:[..this.state.list,'new value'] });
您可以直接使用传播运算符设置setState ..希望它可以工作