我的代码有效,但是我有一个最佳实践问题:状态中有一组对象,并且用户交互一次将更改一个对象的值。 据我所知,我不应该直接更改状态,setState而是应该始终使用。如果我想不惜一切代价避免这种情况,我将通过迭代深度克隆数组,然后更改克隆。然后将状态设置为克隆。我认为避免改变以后会改变的状态只是降低了我的表现。
setState
详细版本: this.state.data是对象数组。它代表论坛中的主题列表,并且收藏夹按钮将切换,调用clickCollect()。由于我在状态中有一个数组,因此当我更改一项的is_collected属性时,我需要创建要使用的数组副本,并在更改为新值后,可以将其设置为状态。
clickCollect()
var data = this.state.data.slice(0); data[index].is_collected = !data[index].is_collected; this.setState({data: data});
var data = this.state.data:这会将指针复制到数组,而push(),shift()等将直接更改状态。双方data并this.state.data会受到影响。
var data = this.state.data
data
this.state.data
var data = this.state.data.slice(0):这将形成一个浅表克隆,push和shift不会更改状态,但是在我的克隆中,我仍然具有指向状态数组元素的指针。因此,如果我更改了data[0].is_collected,那么也会更改this.state.data[0].is_collected。这发生在我打电话之前setState()。
var data = this.state.data.slice(0)
data[0].is_collected
this.state.data[0].is_collected
setState()
通常我应该这样做:
var data = []; for (var i in this.state.data) { data.push(this.state.data[i]); }
然后,我更改index处的值,如果为false则将其设置为true,否则将其设置为false:
data[index].is_collected = !data[index].is_collected;
并更改状态:
this.setState({data: data});
考虑到我的数组比较大还是很大,我猜想这个迭代会降低我的APP的性能。如果我知道出于任何原因这是正确的方法,我将支付该费用。但是,在此函数(clickCollect)中,我总是将新值设置为state,我不是在等待错误的API响应,该响应会说停止进行更改。在所有情况下,新值都会进入状态。实际上,我setState只要求UI再次呈现。所以问题是:
clickCollect
for var i in ...
.slice(0)
data = this.state.data
我的代码经过简化,并且为简化起见,API调用被删去。
这是一个初学者的问题,因此也欢迎使用完全不同的方法。或链接到其他问答。
> import React from 'react'; > > var ForumList = React.createClass({ > render: function() { > return <div className="section-inner"> > {this.state.data.map(this.eachBox)} > </div> > }, > eachBox: function(box, i) { > return <div key={i} className="box-door"> > <div className={"favorite " + (box.is_collected ? "on" : "off")} > onTouchStart={this.clickCollect.bind(null, i)}> > {box.id} > </div> > </div> > }, > getInitialState: function() { > return {data: [ > { > id: 47, > is_collected: false > }, > { > id: 23, > is_collected: false > }, > { > id: 5, > is_collected: true > } > ]}; > }, > clickCollect: function(index) { > var data = this.state.data.slice(0); > data[index].is_collected = !data[index].is_collected; > this.setState({data: data}); > } > }); > > module.exports = ForumList;
就我个人而言,我并不总是遵循规则,如果您真的了解自己想做的事情,那么我认为这不是问题。
在这种情况下,改变状态并setState像这样再次调用即可
this.state.data[index].is_collected = !this.state.data[index].is_collected; this.setState({data: this.state.data});
您应避免更改状态的原因是,如果您引用this.state.data并setState多次调用,则可能会丢失数据:
const myData = this.state.data myData[0] = 'foo' this.setState({ data: myData }) // do something... // ... const someNewData = someFunc() this.setState({ data: someNewData }) myData[1] = 'bar' // myData is still referencing to the old state this.setState({ data: myData }) // you lose everything of `someNewData`
如果您真的对此感到担心,请访问immutable.js