这个例子有点做作,但请耐心等待。假设我在React组件中有两个函数作为成员:
var OrderApp = React.createClass({
getInitialState: function() {
return {
selectedOrders: {},
selectedLineItems: {}
};
},
setOrderSelected: function(order, newSelectedState) {
var mutation = {};
mutation[order.id] = {$set: newSelectedState};
var newSelectedOrders = React.addons(this.state.selectedOrders, mutation);
_.each(order.lineItems, function(lineItem) {
setLineItemSelected(lineItem, newSelectedState);
});
this.setState({selectedOrders: newSelectedOrders});
},
setLineItemSelected: function(lineItem, newSelectedState) {
var mutation = {};
mutation[lineItem.id] = {$set: newSelectedState};
var newSelectedLineItems = React.addons(this.state.selectedLineItems, mutation);
this.setState({seelctedLineItems: newSelectedLineItems});
}
});
在调用OrderApp.setOrderSelected(order,true)完成时,只有最后一个lineItem选中状态似乎在我的组件状态中发生了变化。我猜测这是因为React正在调用setState,所以当我调用时:
var newSelectedLineItems = React.addons(this.state.selectedLineItems, mutation);
在第二个函数中,我每次都会获取原始状态,因此只有最后一个突变生效。
我是否应该收集父函数中的所有状态突变并且只调用一次setState?这对我来说有点笨拙,我想知道我是否错过了一个更简单的解决方案。
答案 0 :(得分:3)
在组件内的给定执行线程中,您不应该多次调用this.setState
。
所以你有几个选择:
使用forceUpdate而不是setState
您无需使用this.setState
- 您可以直接修改状态,并在完成后使用this.forceUpdate
。
这里要记住的主要事情是,一旦开始直接修改this.state
,就应该将其视为污点。 IE:在调用this.forceUpdate
之后,不要使用您知道自己修改过的州或属性。这通常不是问题。
当你在this.state
内处理嵌套对象时,我绝对更喜欢这种方法。就个人而言,我不是React.addons.update
的忠实粉丝,因为我发现语法非常笨重。我更喜欢直接修改forceUpdate
。
创建一个传递的对象,直到最终在setState中使用它
收集所有更改的对象,在执行执行结束时传递给this.setState
。
答案 1 :(得分:1)
不幸的是,这是浅合并的问题。您必须收集更新,并一次应用它们。
对我来说感觉有点笨拙
这是一个非常好的迹象,你应该使用mixin!这段代码看起来非常糟糕,但是当你使用它时,你可以假装它看起来很漂亮。
var React = require('react/addons');
var UpdatesMixin = {
componentDidMount: function(){
this.__updates_list = [];
},
addUpdate: function(update){
this.__updates_list.push(update);
if (this.__updates_list.length === 1) {
process.nextTick(function(){
if (!this.isMounted()) {
this.__updates_list = null;
return;
}
var state = this.__updates_list.reduce(function(state, update){
return React.addons.update(state, update);
}, this.state);
this.setState(state);
this.__updates_list = [];
}.bind(this));
}
}
};
它缓冲同步发生的所有更新,将它们应用于this.state,然后执行setState。
用法如下所示(有关完整演示,请参阅requirebin)。
this.addUpdate({a: {b: {$set: 'foo'}};
this.addUpdate({a: {c: {$set: 'bar'}};
有些地方可以对其进行优化(例如,通过合并更新对象),但您可以在不更改组件的情况下执行此操作。