从自定义对象数组填充树视图。递归调用

Fill treeview from custom array of objects. Recursion call

我正在使用 treeview 来显示我的分层数据。

我有以下对象数组:

const data = [
      { id: 1, hierarchyid: "/", level: 0, name: "Mhz" },
      { id: 2, hierarchyid: "/2/", level: 1, name: "SMT" },
      { id: 3, hierarchyid: "/3/", level: 1, name: "QC" },
      { id: 4, hierarchyid: "/3/4/", level: 2, name: "Tester" },
      { id: 5, hierarchyid: "/3/5/", level: 2, name: "Operator" },
    ];

我需要用这些数据填充我的树视图。 到目前为止我做了什么:

getTreeItems(node, nodes) {
    const filtered = nodes.filter(
      (n) => n.hierarchyid.includes(node.hierarchyid) && n.level != node.level
    );

    return (
      <TreeItem
        key={node.id}
        nodeId={node.hierarchyid}
        label={node.name}
        onClick={() => onClicked(node)}
      >
        {filtered.length > 0
          ? filtered.map((node) => this.getTreeItems(node, filtered))
          : null}
      </TreeItem>
    );
  }

和渲染:

render() {
    // The data comes from Server
    const data = [
      { id: 1, hierarchyid: "/", level: 0, name: "Mhz" },
      { id: 2, hierarchyid: "/2/", level: 1, name: "SMT" },
      { id: 3, hierarchyid: "/3/", level: 1, name: "QC" },
      { id: 4, hierarchyid: "/3/4/", level: 2, name: "Tester" },
      { id: 5, hierarchyid: "/3/5/", level: 2, name: "Operator" },
    ];
    return (
      <TreeView
        aria-label="file system navigator"
        defaultCollapseIcon={<ExpandMoreIcon />}
        defaultExpandIcon={<ChevronRightIcon />}
        sx={{ height: "auto", flexGrow: 1, width: "auto", overflowY: "auto" }}
      >
        {this.getTreeItems(
          { id: 1, hierarchyid: "/", level: 0, name: "Mhz" },
          data
        )}
      </TreeView>
    );
  }
}

这给我的观点是:

+Mhz
 +SMT
 +QC
  +Tester
  +Operator
 +Tester    // they shouldn't be displayed
 +Operator // they have already rendered as child under QC

我的问题是无法排除已经渲染的节点。

更新

MUI TreeView 支持其节点的特殊 JSON 数据。所以将 array 转换为 JSON 也解决了问题。类似的东西:

const data = {
      id: 1,
      hierarchyid: "/",
      level: 0,
      name: "Mhz",
      children: [
        {
          id: 2,
          hierarchyid: "/2/",
          level: 1,
          name: "SMT"
        },
        {
          id: 3,
          hierarchyid: "/3/",
          level: 1,
          name: "QC",
          children: [
            {
              id: 4,
              hierarchyid: "/3/4/",
              level: 2,
              name: "Tester"
            },
            {
              id: 5,
              hierarchyid: "/3/5/",
              level: 2,
              name: "Operator"
            }
          ]
        }
      ]
    };

对象数组来自服务器,那么如何从数组数据中创建这个Json?

所以我查看了文档,他们清楚地提到了一种设计数据对象的方法,这样就可以在不重复多个节点的情况下显示层次结构。

Try going through this once 并根据文档更改渲染函数,您可能会得到想要的结果。

const data: RenderTree = {
  id: "root",
  name: "Mhz",
  children: [
    {
      id: "1",
      name: "SMT"
    },
    {
      id: "3",
      name: "QZ",
      children: [
        {
          id: "4",
          name: "Tester"
        },
        {
          id: "4",
          name: "Operator"
        }
      ]
    }
  ]
};

如果我们编写一个快速函数来测试一个层次结构 id 是否是另一个层次结构的直接后代,那么我们可以用它来编写一个简单的递归版本:

const isChild = (prefix) => ({hierarchyid}) =>
  hierarchyid .startsWith (prefix) 
  && /^[^\/]*\/$/ .test (hierarchyid .slice (prefix .length))

const nest = (xs, prefix = '') => 
  xs .filter (isChild (prefix)) .map ((x, _, __, children = nest (xs, x .hierarchyid)) => ({
    ...x, 
    ... (children .length ? {children} : {})
  }))

const data = [{id: 1, hierarchyid: "/", level: 0, name: "Mhz"}, {id: 2, hierarchyid: "/2/", level: 1, name: "SMT"}, {id: 3, hierarchyid: "/3/", level: 1, name: "QC"}, {id: 4, hierarchyid: "/3/4/", level: 2, name: "Tester"}, {id: 5, hierarchyid: "/3/5/", level: 2, name: "Operator"}]


console .log (nest (data))
.as-console-wrapper {max-height: 100% !important; top: 0}

isChild 检查层次结构 id 是否以我们的前缀开头,如果其余部分只有一个 '/',则在最后。

nest 并没有想象中的那么高效,因为它会为每个节点扫描整个数组。但我不会担心,直到我有数万个条目。

如果你不介意在你的叶子上有一些空的 children 数组,它仍然更简单:

const nest = (xs, prefix = '') => 
  xs .filter (isChild (prefix)) .map ((x) => ({
    ...x,
    children: nest (xs, x .hierarchyid)
  }))