Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to manage state in a tree component in reactjs

I've been struggling this for a couple of days, trying to figure out the "react" way to do it.

Basically, I have a tree, a list of lists (of lists ...) that can be arbitrarily nested, and I want a component that will display this and also enable rearrangement.

Here's my data:

var data = [{
      id: 1
    }, {
      id: 2, children: [
        {
          id: 3, children: [{id: 6}]
        }, {
          id: 4
        }, {
          id: 5
        }]
    }]

My first pass was to just have a single "tree" component that builds the nested lists of DOM elements in its render function (look at the code here). That actually worked pretty well for small numbers of elements, but I want to be able to support hundreds of elements, and there was a very high re-render cost when an element was moved within the tree (~600ms when there were a few hundred elements).

So I think I'll have each "node" of the tree be it's own instance of this component. But here's my question (sorry for the long intro):

Should each node dynamically query for the list it's children's IDs from a central "database" and store that in state? Or should the top-most node load the whole tree and pass everything down through props?

I'm still trying to wrap my mind around how state & props should be handled & divvied up.

Thanks

like image 231
Jared Forsyth Avatar asked Dec 10 '13 19:12

Jared Forsyth


2 Answers

I wanted to try out the tree structure with React and came up with a simple component that hides subtrees when you click on <h5>. Everything is a TreeNode. Is this similar to what you were thinking?

You can see it in action in this JSFiddle: http://jsfiddle.net/ssorallen/XX8mw/

TreeNode.jsx:

var TreeNode = React.createClass({
  getInitialState: function() {
    return {
      visible: true
    };
  },
  render: function() {
    var childNodes;
    if (this.props.node.childNodes != null) {
      childNodes = this.props.node.childNodes.map(function(node, index) {
        return <li key={index}><TreeNode node={node} /></li>
      });
    }

    var style = {};
    if (!this.state.visible) {
      style.display = "none";
    }

    return (
      <div>
        <h5 onClick={this.toggle}>
          {this.props.node.title}
        </h5>
        <ul style={style}>
          {childNodes}
        </ul>
      </div>
    );
  },
  toggle: function() {
    this.setState({visible: !this.state.visible});
  }
});

bootstrap.jsx:

var tree = {
  title: "howdy",
  childNodes: [
    {title: "bobby"},
    {title: "suzie", childNodes: [
      {title: "puppy", childNodes: [
        {title: "dog house"}
      ]},
      {title: "cherry tree"}
    ]}
  ]
};

React.render(
  <TreeNode node={tree} />,
  document.getElementById("tree")
);
like image 81
Ross Allen Avatar answered Nov 20 '22 15:11

Ross Allen


Seems like it'd be nicer to pass everything down as props, as this will prevent you from the trouble of managing individual insertion/deletion. Also, like the comments said, the key attributes prevents a huge chunk of unnecessary re-rendering.

You might want to check this link: http://facebook.github.io/react/blog/2013/11/05/thinking-in-react.html. It describes the kind of dilemma you're having and how to approach it.

(Coincidentally, I've made a react tree view a while ago: https://github.com/chenglou/react-treeview. Take whatever you want from it!)

like image 26
chenglou Avatar answered Nov 20 '22 13:11

chenglou