正确修改ReactJS中的状态数组
我想添加一个元素到state
数组的末尾,这是正确的方法吗?
this.state.arrayvar.push(newelement); this.setState({arrayvar:this.state.arrayvar});
我担心的是,用push
修改arrays可能会造成麻烦 – 是否安全?
制作数组副本的替代方法,以及setState
,这看起来很浪费。
React文档说:
把这个状态看作是不可变的。
您的push
将直接改变状态,这可能会导致错误代码,即使您之后再次“重置”状态。 F.ex,可能会导致像componentDidUpdate
这样的生命周期方法不会触发。
你会提到一个更好的select:
var arrayvar = this.state.arrayvar.slice() arrayvar.push(newelement) this.setState({ arrayvar: arrayvar })
与使用非标准状态修改可能遇到的错误相比,内存“浪费”不是问题。
替代语法
你可以使用concat
来获得更清晰的语法,因为它返回一个新的数组:
this.setState({ arrayvar: this.state.arrayvar.concat([newelement]) })
在ES6中,您可以使用Spread Operator :
this.setState({ arrayvar: [...this.state.arrayvar, newelement] })
在以后的React版本中,推荐的方法是使用更新函数而不是使用更多function语法的对象:
this.setState(prevState => ({ arrayvar: [...prevState.arrayvar, newelement] }))
最简单的,如果你正在使用ES6
。
initialArray = [1, 2, 3]; newArray = [ ...initialArray, 4 ]; // --> [1,2,3,4]
新数组将会是[1,2,3,4]
在React中更新你的状态
this.setState({arrayvar:[...this.state.arrayvar, newelement]});
了解有关数组解构的更多信息
正如评论中提到的@nilgun,你可以使用反应不变性帮手 。 我发现这是超级有用的。
从文档:
简单的推动
var initialArray = [1, 2, 3]; var newArray = update(initialArray, {$push: [4]}); // => [1, 2, 3, 4]
initialArray仍然是[1,2,3]。
React可能会批量更新,因此正确的方法是为setState提供执行更新的function。
对于React更新插件,以下将可靠地工作:
this.setState( (state) => update(state, {array: {$push: [4]}}) );
或为concat():
this.setState( (state) => { state.array = state.array.concat([4]); return state; });
下面显示了https://jsbin.com/mofekakuqi/7/edit?js输出的例子,如果你弄错了会发生什么。;
setTimeout()调用正确地添加了三个项目,因为React不会在setTimeoutcallback中批量更新(请参阅https://groups.google.com/d/msg/reactjs/G6pljvpTGX0/0ihYw2zK9dEJ )。
车上的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'));
ES6
最简单的方法是:
this.setState(prevState => ({ array: [...prevState.array, newElement] }))
如果你愿意使用推,你可以做这样的事情:
// wrong because push modify the array directly this.setState(prevState => ({ arrayvar: prevState.arrayvar.push(someElemet) && prevState.arrayvar, }));
当然,更好的解决scheme是通过使用concat , slice或spread来避免突变。
看到这个video教程更多的解释。