Как управлять состоянием в древовидной компоненте в реакции

Я боролся с этим в течение нескольких дней, пытаясь понять способ "реагировать" на это.

В принципе, у меня есть дерево, список списков (списков...), которые могут быть произвольно вложенными, и я хочу, чтобы компонент отображал это, а также разрешал перегруппировку.

Здесь мои данные:

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

Мой первый проход состоял только в том, чтобы иметь только один "древовидный" компонент, который строит вложенные списки элементов DOM в своей функции рендеринга (смотрите здесь код). Это действительно хорошо работает для небольшого количества элементов, но я хочу иметь возможность поддерживать сотни элементов, и была очень высокая стоимость рендера, когда элемент был перемещен внутри дерева (~ 600 мс, когда было несколько сотен элементы).

Поэтому я думаю, что каждый "node" дерева будет собственным экземпляром этого компонента. Но вот мой вопрос (извините за длинное введение):

Если каждый node динамически запрашивает список, это идентификаторы детей из центральной "базы данных" и хранят это в состоянии? Или должен ли самый верхний node загружать все дерево и пропускать все через реквизиты?

Я все еще пытаюсь задуматься о том, как нужно обрабатывать состояние и реквизит и разворачиваться.

Спасибо

Ответ 1

Я хотел попробовать древовидную структуру с помощью React и придумал простой компонент, скрывающий поддеревья, когда вы нажимаете <h5>. Все есть TreeNode. Это похоже на то, о чем вы думали?

Вы можете увидеть это в действии в этом 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")
);

Ответ 2

Похоже, было бы лучше сдать все как реквизит, так как это помешает вам справиться с управлением отдельной вставкой/удалением. Кроме того, как и упомянутые комментарии, атрибуты key предотвращают огромный фрагмент ненужного повторного рендеринга.

Вы можете проверить эту ссылку: http://facebook.github.io/react/blog/2013/11/05/thinking-in-react.html. В нем описывается дилемма, с которой вы сталкиваетесь, и подход к ней.

(По совпадению, я сделал последнее дерево реакции: https://github.com/chenglou/react-treeview. Возьмите все, что от вас хотите!)

Ответ 3

Вот краткий пример создания дерева с помощью React и Flux. http://www.syntaxsuccess.com/viewarticle/5510d81be1ce52d00e93da55

Компонент React является рекурсивным, а управление состоянием выполняется с помощью Flux.