2014-10-03 53 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