Skip to content Skip to sidebar Skip to footer

Pass New Server Data To React.js Components

I'm new to React.js and struggling to understand few core concepts to decide should we use this library for our application. My main problem is actually handling update in model th

Solution 1:

Calling renderComponent again with the same component but different data is equivalent to calling component.setProps(). So either keep all the models as state in the least common denominator, or just call setProps/renderComponent again when it changes.

Solution 2:

If you pass the data as props down to your child component, you can simply update it at a higher level and it will force a render to all components that uses the same property object. Consider this simple example:

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

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

Now, when the user clicks the button you change the property on the Hello component, but since you passed the same property (or data) object to the children, they will react to it and update it’s shadow DOM accordingly.

Here is a fiddle of what I mean: http://jsfiddle.net/xkCKR/

If you have an external data object, you can just pass it to the top component. Just remember that this doesn’t mean that there is a two-way binding:

// simple example of a data modelvarData = { name: 'world' };

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

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

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

This works because react uses one-way binding of properties. But if say your child component would update it’s properties, it won’t climb up to it’s parent. For that you’ll need the ReactLink add-on or use a pub/sub interface like the one Backbone provides.

Solution 3:

At the moment I know at least three ways to pass new data to a component:

  1. Re-render component. Do not worry about efficiency of this method because React seems to handle this very well. There are nice articles about this: Change And Its Detection In JavaScript Frameworks and Updating with React.render
  2. Use PubSub to allow component to be notified on data change (some helpful examples you can find in the How to communicate between React components post).
  3. Binding with a callback (see three jsfiddles below)

For the third option I was inspired by the answer of StevenH and extended it a little. Please check my implementation at jsfiddle.net/kb3gN/12002/.

varData = { value: 1 };

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

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

varHello = 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: <Worlddata={this.state.data} /></div>
        );
    }
});

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

Also there is an extended version at jsfiddle.net/kb3gN/12007.

functionListenersService(){
    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];
            returntrue;
        }
        returnfalse;
    }
    this.notifyListeners = function(data){
        for (var id in listeners) {
          if(listeners.hasOwnProperty(id)){
            listeners[id](data);
          }
        }
    }
}

functionDataService(ListenersService){
    varData = { value: 1 };
    var self = this;

    var listenersService = newListenersService();
    this.addListener = listenersService.addListener;
    this.removeListener = listenersService.removeListener;
    this.getData = function(){
        returnData;
    }

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

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

varHello = 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: <Worlddata={this.state.data} /></div>
        );
    }
});

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

This implementation is not completely following the idea of isolated components (because Hello component is dependent on the DataService API), but it can be abstracted further and is up to the app developer which app-specific conventions his components will follow. For example see the mix of the first and second examples at jsfiddle.net/kb3gN/12015 (halloDataStatic object and halloDataDynamic callback)

Note: The ListenersService used in the example is following Observer Pattern and the pattern itself has more cons than pros in many scenarios. But beside that, What I wanted to show with these examples is that there is a way of data binding with a callback

<div id="static"></div>
<divid="dynamic"></div><script>functionListenersService(){
    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];
            returntrue;
        }
        returnfalse;
    }
    this.notifyListeners = function(data){
        for (var id in listeners) {
          if(listeners.hasOwnProperty(id)){
            listeners[id](data);
          }
        }
    }
}

functionDataService(ListenersService){
    varData = { value: 1 };
    var self = this;

    var listenersService = newListenersService();
    this.addListener = listenersService.addListener;
    this.removeListener = listenersService.removeListener;
    this.getData = function(){
        returnData;
    }

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

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

varHello = React.createClass({
    getInitialState: function() {
        var data;
        if(typeofthis.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}: <Worlddata={this.state.data} /></div>
        );
    }
});
</script>React.renderComponent(<HellohalloData={halloDataStatic}name="static"/>, document.getElementById('static'));
React.renderComponent(<HellohalloData={halloDataDynamic}name="dynamic"/>, document.getElementById('dynamic'));

Post a Comment for "Pass New Server Data To React.js Components"