2014-10-03 63 views
2

这个例子有些勉强,但忍耐着我。说我有两个函数作为成员的阵营组成:正确处理多个顺序状态更新

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(订单,真)完成,只有最后LINEITEM选择的状态出现在我的组件的状态已经改变。我猜这是因为REACT为配料对setState的电话,所以当我打电话:

var newSelectedLineItems = React.addons(this.state.selectedLineItems, mutation); 
在第二功能

,我每次拿起原来的状态,所以只有最后一次突变生效。

我应该收集父函数中的所有状态突变,并且只调用一次setState?这对我来说有点笨拙,我想知道我是否错过了一个更简单的解决方案。

回答

2

在给定的组件执行线程中,不应多次调用this.setState

所以,你有两个选择:

使用forceUpdate代替的setState

你没有使用this.setState - 你可以直接修改状态,并使用this.forceUpdate大功告成后。

这里要记住的主要问题是,您应该尽快将this.state视为受污染,只要您开始直接修改它即可。 IE:不要使用状态,或者在调用this.forceUpdate之后才知道您已修改的属性。这通常不是问题。

我绝对喜欢这种方法,当你在处理this.state内的嵌套对象。就个人而言,我不是React.addons.update的巨大粉丝,因为我觉得这个语法非常笨重。我更愿意直接修改和forceUpdate

创建您绕过,直到最后在的setState

使用它的对象收集的所有更改的对象,传递给this.setState在你执行的线程结束。

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)); 
     } 
    } 
}; 

requirebin

,它缓存是同步发生的所有更新,并将其应用于this.state,然后做了的setState。

用法如下所示(请参阅requirebin以获取完整演示)。

this.addUpdate({a: {b: {$set: 'foo'}}; 
this.addUpdate({a: {c: {$set: 'bar'}}; 

有一些地方它可以(通过合并更新的对象,例如)进行优化,但你以后也可以做到不改变你的组件。

+0

作为React的全新产品,我没有考虑过在这里使用Mixin,但是这绝对让人感觉更清爽。我的一个问题涉及在您的解决方案中调用process.nextTick。我能找到的唯一文档表明这是一个Node特定的库。是否有类似的库可用于在客户端上处理时缓冲更新? – tnorwood 2014-10-03 19:16:38

+0

如果你不使用browserify/webpack,你可以下载一个独立的shim:http://wzrd.in/standalone/process%2fbrowser - 大多数人使用cjs模块,你必须自己编译一些库,因为npm通常是唯一的分销渠道。 – FakeRainBrigand 2014-10-03 23:12:45

+0

我真的很喜欢你对我问题的回答。我将Mike的答案标记为仅仅因为它不需要外部依赖。我认为有一个强有力的案例可以让你的答案从更多的ReactJS思维模式中解决问题。谢谢您的帮助。 – tnorwood 2014-10-06 13:19:55