【问题标题】:Add a child to tree with useState使用 useState 将孩子添加到树中
【发布时间】:2020-12-16 07:47:54
【问题描述】:

我有一个带有 React 的简单树,这棵树的数据来自根节点,它递归地渲染它的子节点 -

<div className="Tree">
  <div>{props.name}</div>
  <div className="children">
    {props.children &&
      props.children.map((item) => {
        return <TreeNode name={item.name} children={item.children} />;
      })}
  </div>
</div>

通过更改 TreeNode 组件并使用 useState 我如何选择将子节点添加到树中的任何节点的操作?

这是我到目前为止的代码 - Demo

(您可以在按钮中实现添加子项的操作,并为新子项指定您想要的任何名称)

【问题讨论】:

  • 在您的示例中,您渲染了一个独立的 TreeComponent,但您希望将树作为状态保持在更高级别。您还应该将键应用于映射元素,以便在状态更改时仅重新呈现必要的内容。请参阅此答案以获取有效的递归示例:Alternately style items in deeply nested lists with React

标签: javascript reactjs react-hooks


【解决方案1】:

这是一个演示。我将每个子节点存储在父组件状态中。输入显示单击添加时正在创建的节点的名称。

https://codesandbox.io/s/react-hooks-counter-demo-forked-b9mx5

import React, { useState } from "react";
import ReactDOM from "react-dom";
import "./styles.css";

const TreeNode = (props) => {
  const [children, setChildren] = useState([]);
  const [input, setInput] = useState(props.name + "-0");

  function addNode(e) {
    e.preventDefault();
    setChildren((children) => [...children, { name: input, children: [] }]);
    setInput(`${props.name}-${children.length + 1}`);
  }

  return (
    <div className="Tree">
      <div>
        <span>{props.name}</span>
        <form onSubmit={addNode}>
          <input
            type="text"
            value={input}
            onChange={(e) => setInput(e.target.value)}
          />
          <button type="submit">Add child</button>
        </form>
      </div>
      <div className="children">
        {children &&
          children.map((item, index) => {
            return <TreeNode key={index} name={item.name} />;
          })}
      </div>
    </div>
  );
};

const rootElement = document.getElementById("root");
ReactDOM.render(<TreeNode name="Node" />, rootElement);

【讨论】:

    【解决方案2】:

    一种方法是在内部状态中复制props.children 并向其添加新子:

    https://codesandbox.io/s/react-hooks-counter-demo-forked-clls0

    const TreeNode = (props) => {
      const [childState, setChildState] = useState(props.children);
      const addChild = () => {
        setChildState((childState) => {
          return [
            ...(childState || []),
            { name: `${props.name}-${childState?.length + 1 || 1}` }
          ];
        });
      };
      return (
        <div className="Tree">
          <div>
            <span>{props.name}</span>
            <button onClick={addChild}>Add child</button>
          </div>
          <div className="children">
            {childState &&
              childState.map((item) => {
                return <TreeNode name={item.name} children={item.children} />;
              })}
          </div>
        </div>
      );
    };
    

    另一种是直接改变treeData并强制更新视图:

    https://codesandbox.io/s/react-hooks-counter-demo-forked-lipgf

    const TreeNode = ({ item }) => {
      const addChild = () => {
        item.children = [
          ...(item.children || []),
          { name: `${item.name}-${item.children?.length + 1 || 1}` }
        ];
        update({});
      };
      return (
        <div className="Tree">
          <div>
            <span>{item.name}</span>
            <button onClick={addChild}>Add child</button>
          </div>
          <div className="children">
            {item.children &&
              item.children.map((item) => {
                return <TreeNode item={item} />;
              })}
          </div>
        </div>
      );
    };
    
    let update;
    const rootElement = document.getElementById("root");
    const App = () => {
      [, update] = useState();
      return <TreeNode item={treeData} />;
    };
    ReactDOM.render(<App />, rootElement);
    

    【讨论】:

      猜你喜欢
      • 2015-01-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-11-24
      • 1970-01-01
      相关资源
      最近更新 更多