2013-12-16 44 views
20

我是React.js的新手,並且很難理解幾個核心概念,以決定是否應該在我們的應用程序中使用此庫。我的主要問題實際上是處理從服務器獲取的模型中的更新。將新的服務器數據傳遞給react.js組件

想象一下,我有一個頁面應該顯示五種不同的模型。我已經按照本文中描述的方式構建了它:http://facebook.github.io/react/blog/2013/11/05/thinking-in-react.html,所以我有「根」組件,其中所有5個模型都通過了,並且使用了道具,它們將會繼承這些模型的組件。所以,現在更新了2個模型(我從我的模型代碼中獲取這些事件,這些事件不在反應組件之中),我需要在UI上反映這一點。做這個的最好方式是什麼?

我在考慮下列選項:

  1. 運行renderComponent用新數據再次,依靠DOM DIFF反應技術。我擔心這一點,因爲我需要對數據進行任何小小的更改。
  2. 爲持有此模型的組件調用setState。通過這種方式,數據變得不是道具,而是說明(根據我的理解)並不是一個好習慣。另外,我沒有看到任何方式來獲取根組件之外的子組件。
  3. 有多個renderComponent調用,所以這樣我就可以訪問任何這個組件的setProps。但是接下來我需要做一些模板工作(讓頁面上的所有容器都可用),並且它會殺死所有的反應思想。
  4. 擁有一個根組件,其中包括向用戶顯示的應用程序中的所有可能模型以及用於更改模型的setProps。在這裏我所關注的,該組件將增長相當大,由點1

成爲「意大利麪條」在某個時刻關注+預先感謝您,並希望我能解釋清楚我的問題。

+1

您的模型層是否使用事件?如果是這樣,你可以使用它們來觸發渲染。 – krs

+0

我已經添加了一個類似的問題關於使用React的骨幹模型,以及當模型更新時應如何更新視圖http://stackoverflow.com/questions/20371566/handling-backbone-model-collection-changes-in-react -js –

+1

您是否找到解決方案? – copndz

回答

4

再次使用相同的組件調用renderComponent但不同的數據等同於調用component.setProps()。因此,要麼將所有模型作爲狀態保留在最小公分母中,要麼在更改時再次調用setProps/renderComponent。

+0

您是否只有一個通過renderComponent創建的根組件?或者你有一個單獨的組件,可以爲應用程序的每個邏輯部分呈現不同的容器?感謝您的回覆,並試圖幫助我! –

4

如果將數據作爲道具傳遞給子組件,則可以在更高級別上更新它,並強制渲染使用相同屬性對象的所有組件。考慮一個簡單的例子:

var World = React.createClass({ 
    render: function() { 
     return <strong>{this.props.name}</strong>; 
    } 
}); 

var Hello = React.createClass({ 
    clickHandler: function() { 
     this.setProps({ name: 'earth' }); 
    }, 
    render: function() { 
     return (
      <div> 
       Hello <World name={this.props.name} /> 
       <button onClick={this.clickHandler}>Click me</button> 
      </div> 
     ); 
    } 
}); 

現在,當用戶點擊該按鈕更改Hello組件上的財產,但因爲你通過了相同的屬性(或數據)對象的孩子,他們會對其做出反應並相應地更新它的影子DOM。

這裏是我的意思小提琴:http://jsfiddle.net/xkCKR/

如果你有一個外部的數據對象,你可以把它傳遞到頂部部件。請記住,這並不意味着有一個雙向綁定:

// simple example of a data model 
var Data = { name: 'world' }; 

var World = React.createClass({ 
    render: function() { 
     return <strong>{this.props.data.name}</strong>; 
    } 
}); 

var Hello = React.createClass({ 
    clickHandler: function() { 
     this.setProps({ 
      data: { name: 'earth' } 
     }); 
    }, 
    render: function() { 
     return (
      <div> 
       Hello <World data={this.props.data} /> 
       <button onClick={this.clickHandler}>Click me</button> 
      </div> 
     ); 
    } 
}); 

React.renderComponent(<Hello data={Data} />, document.body); 

這工作,因爲反應使用單向性的結合。但是如果說你的孩子組件會更新它的屬性,它就不會爬到它的父母身上。爲此,您需要ReactLink add-on或使用像Backbone提供的pub/sub接口。

+3

你從React裏面做的所有事情,我想我想要的是從外部reactjs中「刷新」dom。 – copndz

+0

是的,我也不理解單向概念,這裏是一個射擊綁定,一旦完成,即使我改變了外部模型中的數據,這在渲染類中也沒有效果:this.props.model.modelproperty沒有檢查更新 –

+2

您不應該更改道具,您需要通過調用setState來反映數據的任何更改,只有這樣纔會觸發受影響組件和子組件的重新渲染。 – markus

4

目前我知道至少有三種方式將新數據傳遞給一個組件:

  1. 重新渲染組件。不要擔心這種方法的效率,因爲React似乎處理得很好。有關於此的好文章:Change And Its Detection In JavaScript FrameworksUpdating with React.render
  2. 使用PubSub允許在數據更改時通知組件(在How to communicate between React components文章中可找到一些有用的示例)。
  3. 有回調綁定(見下面的第三jsfiddles)

對於我被StevenH答案激發了第三個選項,並延長了一點。 請檢查我的執行j sfiddle.net/kb3gN/12002/

var Data = { value: 1 }; 

var dataChange = function(callback){ 
    if(callback){ 
     callback(Data); 
     setInterval(function(){ 
      Data.value++; 
      callback(Data); 
     }, 1000); 
    } 
    return Data; 
}; 

var World = React.createClass({ 
    render: function() { 
     return <strong>{this.props.data.value}</strong>; 
    } 
}); 

var Hello = React.createClass({ 
    getInitialState: function() { 
     return { 
      data: this.props.dataChange() 
     }; 
    }, 
    componentDidMount: function() { 
     this.props.dataChange(this.updateHandler) 
    }, 
    updateHandler: function(data) { 
     this.setState({ 
      data: data 
     }); 
    }, 
    render: function() { 
     return (
      <div> 
       Value: <World data={this.state.data} /> 
      </div> 
     ); 
    } 
}); 

React.renderComponent(<Hello dataChange={dataChange} />, document.body); 

此外,還有一個擴展版本jsfiddle.net/kb3gN/12007

function ListenersService(){ 
    var listeners = {}; 
    this.addListener = function(callback){ 
     var id; 
     if(typeof callback === 'function'){ 
      id = Math.random().toString(36).slice(2); 
      listeners[id] = callback; 
     } 
     return id; 
    } 
    this.removeListener = function(id){ 
     if(listeners[id]){ 
      delete listeners[id]; 
      return true; 
     } 
     return false; 
    } 
    this.notifyListeners = function(data){ 
     for (var id in listeners) { 
      if(listeners.hasOwnProperty(id)){ 
      listeners[id](data); 
      } 
     } 
    } 
} 

function DataService(ListenersService){ 
    var Data = { value: 1 }; 
    var self = this; 

    var listenersService = new ListenersService(); 
    this.addListener = listenersService.addListener; 
    this.removeListener = listenersService.removeListener; 
    this.getData = function(){ 
     return Data; 
    } 

    setInterval(function(){ 
     Data.value++; 
     listenersService.notifyListeners(Data); 
    }, 1000); 
} 
var dataSevice = new DataService(ListenersService); 

var World = React.createClass({ 
    render: function() { 
     return <strong>{this.props.data.value}</strong>; 
    } 
}); 

var Hello = React.createClass({ 
    getInitialState: function() { 
     return { 
      data: this.props.dataService.getData() 
     }; 
    }, 
    componentDidMount: function() { 
     this.props.dataService.addListener(this.updateHandler) 
    }, 
    updateHandler: function(data) { 
     this.setState({ 
      data: data 
     }); 
    }, 
    render: function() { 
     return (
      <div> 
       Value: <World data={this.state.data} /> 
      </div> 
     ); 
    } 
}); 

React.renderComponent(<Hello dataService={dataSevice} />, document.body); 

此實現不完全以下隔離組件(因爲你好組件依賴於DataService在API)的想法,但它可以被進一步抽象,它的最大的應用程序開發人員,其具體應用的約定他的組件將遵循。例如,請參閱jsfiddle.net/kb3gN/12015(halloDataStatic對象和halloDataDynamic回調)中的第一個和第二個示例的組合

注意:示例中使用的ListenersService遵循Observer Pattern,在許多情況下,模式本身比專業人員更具缺點。但除此之外,我想通過這些示例展示的是,有一種數據與回調綁定的方式

<div id="static"></div> 
<div id="dynamic"></div> 
<script> 

function ListenersService(){ 
    var listeners = {}; 
    this.addListener = function(callback){ 
     var id; 
     if(typeof callback === 'function'){ 
      id = Math.random().toString(36).slice(2); 
      listeners[id] = callback; 
     } 
     return id; 
    } 
    this.removeListener = function(id){ 
     if(listeners[id]){ 
      delete listeners[id]; 
      return true; 
     } 
     return false; 
    } 
    this.notifyListeners = function(data){ 
     for (var id in listeners) { 
      if(listeners.hasOwnProperty(id)){ 
      listeners[id](data); 
      } 
     } 
    } 
} 

function DataService(ListenersService){ 
    var Data = { value: 1 }; 
    var self = this; 

    var listenersService = new ListenersService(); 
    this.addListener = listenersService.addListener; 
    this.removeListener = listenersService.removeListener; 
    this.getData = function(){ 
     return Data; 
    } 

    setInterval(function(){ 
     Data.value++; 
     listenersService.notifyListeners(Data); 
    }, 100); 
} 
var dataSevice = new DataService(ListenersService); 
var halloDataDynamic = function(callback){ 
    var data = dataSevice.getData(); 
    if(callback){ 
     dataSevice.addListener(function(data){ 
      callback(data); 
     }); 
    } 
    return data; 
}; 
var halloDataStatic = dataSevice.getData(); 

var World = React.createClass({ 
    render: function() { 
     return <strong>{this.props.data.value}</strong>; 
    } 
}); 

var Hello = React.createClass({ 
    getInitialState: function() { 
     var data; 
     if(typeof this.props.halloData === 'function'){ 
      data = this.props.halloData(this.updateHandler) 
     } 
     else data = this.props.halloData; 
     return { 
      data: data 
     }; 
    }, 
    updateHandler: function(data) { 
     this.setState({ 
      data: data 
     }); 
    }, 
    render: function() { 
     return (
      <div> 
       Value {this.props.name}: <World data={this.state.data} /> 
      </div> 
     ); 
    } 
}); 
</script> 

React.renderComponent(<Hello halloData={halloDataStatic} name="static"/>, document.getElementById('static')); 
React.renderComponent(<Hello halloData={halloDataDynamic} name="dynamic"/>, document.getElementById('dynamic')); 
相關問題