React.js:对外部对象的变化做出反应

时间:2017-01-04 17:44:34

标签: javascript reactjs

在阅读官方的 react.js 文档后,我了解它应该如何以一种好的方式工作,例如

  1. 我有初始组件状态的项目列表
  2. 通过 setState 添加新项目将更新状态并触发UI的更新
  3. 如果我将外部对象用作某些全局数组的模型,我应该怎么办?某些非 react.js 部分代码可用,或者将来可以在某处使用Web套接字进行修改?在每个动作之后调用 ReactDOM.render 是一个好方法吗?从性能的角度来看,AFAIK应该可以正常工作。

2 个答案:

答案 0 :(得分:1)

您仍然使用setState

let React = require('React');
let externalThing = require('tools/vendor/whoever/external-lib');

class MyComponent extends React.Component {
  getInitialState() {
    // This assumes your external thing is written by someone who was
    // smart enough to not allow direct manipulation, but made sure
    // to use API functions that allow for event handling etc.
    externalThing.registerChangeListener(this.updateBasedOnChanges);
    return { data: externalThing.data } 
  }
  updateBasedOnChanges() {
    // note: this does NOT automatically trigger render(), because
    // React is smarter than that. It will only trigger render() if
    // it sees that this new 'data' is different (either by being a
    // different thing entirely, or having different content)
    this.setState({
      data: externalThing.data
    });
  }
  render() {
    // ...
  }
}

如果您正在使用的外部内容写得非常糟糕且您必须直接操作其数据,那么您的第一步是为其编写API,以便直接操作该数据。

let externalData = require('externaldata') // example: this is a shared array
let ExternalDataAPI = new ExternalDataAPI(externalData);
...

然后确保API具有所有更新和事件挂钩:

class ExternalDataAPI {
  constructor(data) {
    this.data = data;
    this.listeners = [];
  }
  addListener(fn) {
    this.listeners.push(fn);
  }
  update(...) {
    // do something with data
    this.listeners.forEach(fn => fn());
  }
  ...
}

或者,有一些框架已经为你做了这些(助焊剂等),但它们也在某种程度上规定了“应该做多少”的事情,这可能对你的需要来说太过分了。

答案 1 :(得分:0)

由于您的问题是以可管理的方式组织代码,我首先建议将ReactJS与Flux类型的框架(如Redux或Relay)配对。

如果您想暂时跳过它,那么您可以使用层次结构顶部的一些反应组件来组织项目,以存储和检索数据。例如,在这样的组件中,在componentWillMount方法中,您可以启动setTimeout,定期检查全局数组并在适当时调用setState。然后,render方法应包含将此状态作为props接收的子组件。

以下是一个例子。显然,定时器可以替换为您用于订阅数据更改的任何方法。



// your global object
var globalState = {name: "Sherlock Holmes"}

function onData(callback) {
  setInterval(function(){
    callback(globalState)
  }, 1500)
}

var Child = React.createClass({  
  render: function() {
    return <h1>Hello, {this.props.name}</h1>;
  }
});

var Root = React.createClass({
  getInitialState: function() { 
    return {} 
  },
  componentWillMount: function() {
  	var that = this;
    this.props.onData(function(data){
    	that.setState({external: data})
    })
  },
  render: function() {
    if (this.state.external)
    	return <Child name={this.state.external.name}/>
    else
    	return <div>loading...</div>;
  }
});


ReactDOM
.render(<Root onData={onData} />, document.getElementById('container'))
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="container"></div>
&#13;
&#13;
&#13;