Justin Rassier Justin Rassier - 1 month ago 16
Javascript Question

ReactJS data flow with deep hierarchical data

I'm exploring ReactJS and trying to get a grasp of the core concepts. I started piecing a prototype of an application I am working on that has the following hierarchy of


  • Customer

    • Locations

      • Addresses

      • Contacts





The page I am working on would be an input form for a Customer and all of its related children. Each of these sections would have some text inputs to house data, so they seemed like a natural place to house a hierarchy of components.

From everything I have read about ReactJS, if you are going to manage state, you should do so in the common ancestor of all the controls. This means that any changes in the child should bubble the event up to the keeper of the state to handle changes. This should then update the state and any changes will be re-rendered. This makes sense in simple scenarios, but that brings me to my slightly more complicated hierarchy.


  • If a change happens down in one of the many Addresses, am I supposed to bubble up that event to the location then to the Customer?

  • If so, what is the best way to tell state which specific address changed?

  • If you have to call up through each level of the hierarchy, wouldn't that make a lot of extra boilerplate to propagate a simple change?

  • Should I be attaching to the onChange event on each text box, or should I wait until I submit the form to gather the data?



React talks about ReactLink (https://facebook.github.io/react/docs/two-way-binding-helpers.html) as a way to manage more complex data binding, but doesn't give a great example of how to manage it with a larger hierarchy. Also, it states that most application shouldn't need this. Well, this application really isn't complicated, just a couple nested controls with shared state. This is where React is supposed to shine, so I wouldn't think to immediately jump to the edge case solutions.

Answer

I recently faced the same puzzle - the React docs are not very complete in this area. This is one way I found to work:

var Parent = React.createClass({
    mixins: [React.addons.LinkedStateMixin],

    getInitialState: function() {
        return {
            p: 'Hello World',
            q: 'Click me if I\'m pink!',
            r: 'A'
        };
    },
    render: function() {
        return (
            <div className='parent'>
                <p>
                    <h3>Parent</h3>
                    <tt>
                        p: {this.state.p}<br />
                        q: {this.state.q}<br />
                        r: {this.state.r}
                    </tt>
                </p>

                <Child q = {this.linkState('q')}
                       p = {this.linkState('p')}
                       r = {this.linkState('r')} />
            </div>
        );
    }
});
var Child = React.createClass({
    clicked: function() {
        this.props.q.requestChange("Thank you :)");
    },
    render: function() {
        return (
            <div className='child'>
                <h3>Child</h3>

                <p>
                    <input valueLink={this.props.p} />
                </p>

                <p>
                    <tt onClick={this.clicked}>
                        {this.props.q.value}
                    </tt>
                </p>

                <select valueLink={this.props.r}>
                    <option value={'A'}>A</option>
                    <option value={'B'}>B</option>
                </select>
            </div>
        );
    }
});

React.render(<Parent />, document.body)

https://jsfiddle.net/cachvico/p81s75x5/

If anyone has any improvements I'd be glad to hear them!