最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - React.js: react on changes in external object - Stack Overflow

programmeradmin2浏览0评论

After reading official react.js documentation I understand how it should work in a good way, like

  1. I have list of items in initial ponent state
  2. adding new item through setState will update state and trigger update of UI

What should I do if I use external object as model like some global array which should be available for some not react.js parts of code OR could be modified with web sockets somewhere in future? Is calling ReactDOM.render after each action a good way? AFAIK it should work ok from performance point of view.

After reading official react.js documentation I understand how it should work in a good way, like

  1. I have list of items in initial ponent state
  2. adding new item through setState will update state and trigger update of UI

What should I do if I use external object as model like some global array which should be available for some not react.js parts of code OR could be modified with web sockets somewhere in future? Is calling ReactDOM.render after each action a good way? AFAIK it should work ok from performance point of view.

Share Improve this question edited Jan 4, 2017 at 18:24 Maxim Tkachenko asked Jan 4, 2017 at 17:44 Maxim TkachenkoMaxim Tkachenko 5,80810 gold badges42 silver badges75 bronze badges 3
  • the render method of the ponent is called each time it's state changes – Paul Fitzgerald Commented Jan 4, 2017 at 17:52
  • So if I change state by myself (state - I mean any object, not react.js state) and trigger ReactDOM.render for ponent - there is no difference, right? – Maxim Tkachenko Commented Jan 4, 2017 at 17:54
  • I can't say exactly the performance overhead you'll get by calling ReactDOM.render every time your data changes, but seems like overkill and is not the way react docs remend doing things. – Bijou Trouvaille Commented Jan 4, 2017 at 18:08
Add a ment  | 

2 Answers 2

Reset to default 7

You still use setState:

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

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = this.getInitialState();
  }
  getInitialState() {
    // This assumes your external thing is written by someone who was
    // smart enough to not allow direct manipulation (because JS has
    // no way to monitor primitives for changes), and made sure
    // to offer API functions that allow for event handling etc.
    externalThing.registerChangeListener(() => this.updateBasedOnChanges(externalThing));
    return { data: externalThing.data }        
  }
  updateBasedOnChanges(externalThing) {
    // note that setState 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() {
    // ...
  }
}

If the external thing you're using is terribly written and you have to manipulate its data directly, your first step is to write an API for it so you don't directly manipulate that data.

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

And then you make sure that API has all the update and event hooks:

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

Alternatively, there are frameworks that already do this for you (flux, etc) but they also somewhat dictate how many more things "should be done" so that might be overkill for your need.

Since your question is about organizing your code in a manageable way, I would first of all suggest pairing ReactJS with a Flux-type framework, like Redux or Relay.

If you want to skip that for now, then you can organize your project using some react ponents at the top of the hierarchy for storing and retrieving data. For example, in such a ponent, in its ponentWillMount method, you can start a setTimeout that periodically checks your global array and calls setState when appropriate. The render method should then contain child ponents that receive this state as props.

Below is an example. Obviously, the timers can be replaced by whichever method you use to subscribe to your data changes.

// 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 {} 
  },
  ponentWillMount: 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'))
<script src="https://cdnjs.cloudflare./ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare./ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="container"></div>

发布评论

评论列表(0)

  1. 暂无评论