React - 在不使用setState的情况下更改状态:必须避免它吗? [英] React - Changing the state without using setState: Must avoid it?
问题描述
我的代码有效,但我有一个最佳实践问题:我在状态中有一个对象数组,用户交互将一次更改一个对象的值。据我所知,我不应该直接更改状态,我应该总是使用 setState
。如果我想以任何代价避免这种情况,我将通过迭代深度克隆数组,并更改克隆。然后将状态设置为克隆。在我看来,避免改变我以后会改变的状态只会降低我的表现。
My code works, but I have a best practice question: I have an array of objects in the state, and a user interaction will change a value of one object at a time. As far as I know, I'm not supposed to change the state directly, i should always use setState
instead. If I want to avoid that with any price, I will deep clone the array by iteration, and change the clone. Then set the state to the clone. In my opinion avoiding to change the state that I will change later anyway is just decreasing my performance.
详细版本:
this.state.data是一个对象数组。它代表论坛中的主题列表,收藏夹按钮将切换,调用 clickCollect()
。
由于我在状态中有一个数组,当我更改一个项的is_collected属性时,我需要创建一个要使用的数组副本,并在更改为新值后,我可以将其设置为州。
Detailed version:
this.state.data is an array of objects. It represents a list of topics in a forum, and a Favorite button will toggle, calling clickCollect()
.
Since I have an array in the state, when I change the is_collected property of one item, I need to create a copy of the array to work with, and after changing to the new value, I can set it to the 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()等会直接改变状态。 数据
和 this.state.data
都会受到影响。
var data = this.state.data
: This would copy the pointer to the array and push(), shift(), etc would alter the state directly. Both data
and this.state.data
will be affected.
var data = this.state.data.slice(0)
:这使得浅层克隆,推送和移位不会改变状态,但在我的克隆中我仍然有指向状态数组元素的指针。因此,如果我更改 data [0] .is_collected
, this.state.data [0] .is_collected
将更改为好。这是在我调用 setState()
之前发生的。
var data = this.state.data.slice(0)
: This makes a shallow clone, push and shift doesn't change the state but in my clone I still have pointers to the elements of the state's array. So if I change data[0].is_collected
, this.state.data[0].is_collected
gets changed as well. This happens before I call setState()
.
通常我应该这样做:
var data = [];
for (var i in this.state.data) {
data.push(this.state.data[i]);
}
然后我改变索引处的值,如果为假,则将其设置为true;如果为真,则将其设置为true:
Then I change the value at index, setting it to true when it's false or false when it's true:
data[index].is_collected = !data[index].is_collected;
并更改状态:
this.setState({data: data});
考虑我的阵列相对较大或非常大,我猜这个迭代会降低我APP的性能。如果我知道这是出于任何原因的正确方法,我会支付这笔费用。但是,在这个函数( clickCollect
)中,我总是将新值设置为状态,我不是在等待一个错误的API响应,它会说停止进行更改。在所有情况下,新值都将进入状态。实际上我只调用 setState
来重新呈现UI。所以问题是:
Consider my array is relatively big or enormously big, I guess this iteration will reduce the performance of my APP. I would pay that cost if I knew that it is the right way for any reason. However, in this function (clickCollect
) I always set the new value to the state, I'm not waiting for a false API response that would say to stop making the change. In all cases, the new value will get into the state. Practically I call setState
only for the UI to render again. So the questions are:
- 在这种情况下我是否必须创建深度克隆? (
for var i in ...
) - 如果没有,那么制作浅层克隆是否有意义(
.slice(0)
)如果我的数组包含对象?正在对数组内部的对象进行更改,因此浅层克隆仍会更改我的状态,就像副本(data = this.state.data
)一样。
- Do I have to create the deep clone in this case? (
for var i in ...
) - If not, does it make sense to make a shallow clone (
.slice(0)
) if my array contains objects? The changes are being made on the objects inside of the array, so the shallow clone still changes my state, just like a copy (data = this.state.data
) would do.
为简单起见,我的代码已经过简化,API调用被删除。
My code is simplified and API calls are cut out for simplicity.
这是一个初学者的问题,所以也欢迎采用完全不同的方法。或链接到其他Q& A。
This is a beginner's question, so a totally different approach is also welcome. Or links to other Q & A.
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;
推荐答案
我个人不喜欢永远不要遵守规则,如果你真的明白你想要做什么,那么我不认为这是一个问题。
Personally I don't always follow the rule, if you really understand what you are trying to do then I don't think it's a problem.
var data = this.state.data.slice(0);
data[index].is_collected = !data[index].is_collected;
this.setState({data: data});
在这种情况下,改变状态并调用 setState
再次像这样很好
In this case, mutating state and calling the setState
again like this is fine
this.state.data[index].is_collected = !this.state.data[index].is_collected;
this.setState({data: this.state.data});
你应该避免改变你的州的原因是,如果你引用了 this.state.data
,多次调用 setState
,您可能会丢失数据:
The reason you should avoid mutating your state is that if you have a reference to this.state.data
, and calling setState
multiple times, you may lose your data:
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
If you really concerned about this, just go for immutable.js
这篇关于React - 在不使用setState的情况下更改状态:必须避免它吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!