Как управлять состоянием, «свернутым» для каждого глубоко вложенного узла в дереве - PullRequest
0 голосов
/ 07 февраля 2019

У меня сложная и динамическая структура данных, например:

const tree = [
  {
    name: "Root Node",
    collapsed: true,
    nodes: [
      {
        name: "Node 1",
        collapsed: true,
        nodes: [
          {
            name: "Sub node"
          }
        ]
      },
      {
        name: "Node 2",
        collapsed: true,
        nodes: [
          {
            name: "Sub node "
          }
        ]
      },
      {
        name: "Node 3",
        collapsed: true,
        nodes: [
          {
            name: "Sub node"
          }
        ]
      }
    ]
  }
];`

Я устанавливаю это как начальное состояние моего компонента.

Затем я отображаю это состояние в виде иерархического дерева в пользовательском интерфейсе.

Когда я щелкаю узел верхнего уровня, я хочу обновить свернутое свойство в состоянии, чтобы оно открывалось и отображалосьследующий набор узлов.

Проблема, с которой я столкнулся, заключается в том, как мне вызвать setState () и обновить эту сложную структуру данных, не вызывая мутации и не делая некрасивые вещи, такие как tree [0] .nodes [0].collapsed: false.

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

handleClick(el, event) {
    this.setState({
        tree: this.findAndUpdateState(event.target.id).bind(this)
    });
}

Итак, для события handleClick узла, который я вызываю, это вызывает findAndUpdateState.

findAndUpdateState(id) {
    this.state.tree.map((node) => {
      //Map over the nodes somehow and find the node that needs its state updated using the ID?
      });
    });
}

Я хочу обновить свернутое свойство узла, который пытался расширить.Но для этого мне нужно пройти через все состояния, а затем создать новую копию состояния, чтобы обновить это свойство.Должен быть более приятный и простой способ, о котором я не думаю.

Ответы [ 2 ]

0 голосов
/ 07 февраля 2019

React неплохо справляется с подобными вещами.

Я использую крючки в React, как они мне нравятся ..:)

Вот рабочий фрагмент ниже..

const tree = [{"name":"Root Node","collapsed":true,"nodes":[{"name":"Node 1","collapsed":true,"nodes":[{"name":"Sub node"}]},{"name":"Node 2","collapsed":true,"nodes":[{"name":"Sub node "}]},{"name":"Node 3","collapsed":true,"nodes":[{"name":"Sub node"}]}]}];

const {useState} = React;


function TreeItem(props) {
  const {item} = props;
  const [collapsed, setCollapsed] = useState(item.collapsed);
  return <div className="item">
    <span onClick={() => setCollapsed(!collapsed)}>{item.name}</span>
    {!collapsed && item.nodes && 
      <div style={{paddingLeft: "1rem"}}>
        <TreeList list={item.nodes}/>
      </div>
    }
  </div>
}

function TreeList(props) {
  const {list} = props;
  return <div>{list.map(f => <TreeItem key={f.name} item={f}/>)}</div>;
}

ReactDOM.render(<TreeList list={tree}/>, document.querySelector('#mount'));
.item {
  cursor: pointer;
  user-select: none;
}
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

<div id="mount"></div>
0 голосов
/ 07 февраля 2019

Вы можете создать компонент Node с его собственным состоянием collapsed:

class Node extends Component {
  state = {
    collapsed: true,
  }

  toggle = () => {
    this.setState(prevState => ({ collapsed: !prevState.collapsed }))
  }

  render() {
    return (
      <div>
        <p onClick={this.toggle}>{this.props.node.name}</p>
        {!this.state.collapsed && (
          <div>{this.props.children}</div>
        )}
      </div>
    )
  }
}

И создать родительский компонент Tree, который рекурсивно отображает все узлы:

const TREE = [{ name: "Root Node", nodes: [...] }]

class Tree extends Component {
  renderNodesRecursively = parent => {
    return (
      <Node node={parent} key={parent.name}>
        {parent.nodes
          ? parent.nodes.map(node => this.renderNodesRecursively(node))
          : null
        }
      </Node>
    )
  }

  render() {
    return TREE.map(node => this.renderNodesRecursively(node))
  }
}

Вы заметите, что состояние детей теряется при каждом переключении родителя.Это "нормально", так как переключение родительского монтирует / размонтирует дочерних элементов.Если вы хотите избежать этого, вы можете заменить этот код

{!this.state.collapsed && (
  <div>{this.props.children}</div>
)}

на

<div style={{ display: this.state.collapsed ? 'none' : 'block' }}>
  {this.props.children}
</div>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...