我的代码有效,但我有一个最佳实践问题:我在状态中有一组对象,用户交互将一次更改一个对象的值。据我所知,我不应该直接改变状态,我应该总是使用setState
。如果我想以任何代价避免这种情况,我将通过迭代深度克隆数组,并更改克隆。然后将状态设置为克隆。在我看来,避免改变我以后会改变的状态只会降低我的表现。
详细版本:
this.state.data 是一个对象数组。它代表论坛中的主题列表,一个收藏按钮将切换,调用clickCollect()
。由于我在 state 中有一个数组,当我更改一个 item 的 is_collected 属性时,我需要创建一个数组的副本来使用,并且在更改为新值后,我可以将其设置为 state。
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.slice(0)
:这会创建一个浅层克隆,push 和 shift 不会改变状态,但在我的克隆中,我仍然有指向状态数组元素的指针。所以如果我改变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]); }
然后我更改索引处的值,当它为假时将其设置为真或为真时设置为假:
data[index].is_collected = !data[index].is_collected;
并更改状态:
this.setState({data: data});
考虑到我的数组比较大或非常大,我猜这次迭代会降低我的APP的性能。如果我知道出于任何原因这是正确的方式,我就会支付这笔费用。然而,在这个函数 ( clickCollect
) 中,我总是将新值设置为状态,我不会等待一个错误的 API 响应,它会说停止进行更改。在所有情况下,新值都会进入状态。实际上,我setState
只要求 UI 再次呈现。所以问题是:
- 在这种情况下,我是否必须创建深度克隆?(
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;