英文:
Rendering Hierarchy based on data using Object.entries
问题
以下是代码的翻译部分:
export const data = {
  "Category 1": [
    {
      key: "1",
      label: "Applications",
      children: [
        {
          key: "3",
          label: "Browser",
          children: [
            {
              key: "4",
              label: "Mozilla",
              children: []
            },
            {
              key: "5",
              label: "Firefox",
              children: []
            }
          ]
        }
      ]
    }
  ],
  "Category 2": [
    {
      key: "2",
      label: "OS",
      children: [
        {
          key: "6",
          label: "Windows",
          children: []
        }
      ]
    }
  ]
};
import React from "react";
import TreeNode from "./TreeNode";
const Tree = ({ data = [] }) => {
  return (
    <div className="d-tree">
      <ul className="d-flex d-tree-container flex-column">
        {data.map((tree) => (
          <TreeNode node={tree} />
        )}
      </ul>
    </div>
  );
};
export default Tree;
希望这有助于你在代码中理解和使用这些部分。
英文:
I am having a object that looks like the following:
export const data = {
  "Category 1": [
    {
      key: "1",
      label: "Applications",
      children: [
        {
          key: "3",
          label: "Browser",
          children: [
            {
              key: "4",
              label: "Mozilla",
              children: []
            },
            {
              key: "5",
              label: "Firefox",
              children: []
            }
          ]
        }
      ]
    }
  ],
  "Category 2": [
    {
      key: "2",
      label: "OS",
      children: [
        {
          key: "6",
          label: "Windows",
          children: []
        }
      ]
    }
  ]
};
This should basically draw a tree with two entries with Category 1 and Category 2 and its children should be drawn recursively.
Category 1
   ---- Applications
          --- Browser
                --- Mozilla
                --- Firefox
Category 2
   ---- OS
          --- Windows
This should be dynamically rendered. The number of first level objects will be determined using the number of keys of the object. I have tried with an array of objects and it works. But when I am having it in the above format, I am unable to render it as a tree. Help would be greatful.
Sandbox: https://codesandbox.io/s/react-hooks-counter-demo-forked-zsxsxh?file=/src/Tree.js
When I am trying it with treeData it works, but with data inside constants.js it doesnt work.
import React from "react";
import TreeNode from "./TreeNode";
const Tree = ({ data = [] }) => {
  return (
    <div className="d-tree">
      <ul className="d-flex d-tree-container flex-column">
        {data.map((tree) => (
          <TreeNode node={tree} />
        ))}
      </ul>
    </div>
  );
};
export default Tree;
I tried with Object.entries to render the tree, it doesnt work
答案1
得分: 1
你的 data 结构与 treeData 不同,尽管子项采用相同的格式。
不是在顶层使用对象:
export const data = {
  "Category 1": [ ... ],
  "Category 2": [ ... ],
};
而应该使用具有 key、label 和 children 的数组:
export const data = [
  {
    key: "Category 1",
    label: "Category 1",
    children: [ ... ]
  }, ...
];
如果你真的不能编辑 data(它就在那里...),你可以使用属性名作为 key 和 label 来映射顶层条目:
const dataAsArray = Object.entries(data).map(([key, value]) =>
  ({ key, label: key, children: value })
)
添加响应评论
如果这是您首选的输入格式,那么您可以将数据转换放入您的 Tree 组件中:
const Tree = ({ data = [] }) => {
  const trees = React.useMemo(() => (
    data instanceof Array
      ? data
      : Object.entries(data).map(
          ([key, children]) => ({ key, label: key, children })
      )
  ), [data]);
    
  return (
    <div className="d-tree">
      <ul className="d-flex d-tree-container flex-column">
        {trees.map((tree) => (
          <TreeNode node={tree} />
        ))}
      </ul>
    </div>
  );
};
英文:
Your data structure is different from treeData, although the children are in the same format.
Instead of an object at the top-level:
export const data = {
  "Category 1": [ ... ],
  "Category 2": [ ... ],
};
you should have an array with key, label and children:
export const data = [
  {
    key: "Category 1",
    label: "Category 1",
    children: [ ... ]
  }, ...
];
If you really can't edit the data (it's right there ...) you could map the top-level entries using the property name as key and label:
const dataAsArray = Object.entries(data).map(([key, value]) =>
  ({ key, label: key, children: value })
)
Added in response to comment
If that's your preferred input format then you could put the data conversion into your Tree component:
const Tree = ({ data = [] }) => {
  const trees = React.useMemo(() => (
    data instanceof Array
      ? data
      : Object.entries(data).map(
          ([key, children]) => ({ key, label: key, children })
      )
  ), [data]);
    
  return (
    <div className="d-tree">
      <ul className="d-flex d-tree-container flex-column">
        {trees.map((tree) => (
          <TreeNode node={tree} />
        ))}
      </ul>
    </div>
  );
};
答案2
得分: 0
In tree.js,你可以验证数据是否不是一个数组并进行转换:
const Tree = ({ data = [] }) => {
  if (!(data instanceof Array)) {
    data = Object.keys(data).map((key) => {
      return { label: key, children: data[key] };
    });
  }
  return (
    <div className="d-tree">
      <ul className="d-flex d-tree-container flex-column">
        {data.map((tree) => (
          <TreeNode node={tree} />
        ))}
      </ul>
    </div>
  );
};
你提供的链接是一个示例的CodeSandbox链接,我不能直接转译它。
英文:
In tree.js you can validate if data is not an array and transform it:
Tree.js
const Tree = ({ data = [] }) => {
  if (!(data instanceof Array)) {
    data = Object.keys(data).map((key) => {
      return { label: key, children: data[key] };
    });
  }
  return (
    <div className="d-tree">
      <ul className="d-flex d-tree-container flex-column">
        {data.map((tree) => (
          <TreeNode node={tree} />
        ))}
      </ul>
    </div>
  );
};
https://codesandbox.io/s/react-hooks-counter-demo-forked-3hxcgq
答案3
得分: 0
以下是您要翻译的内容:
你可以像这样编写Tree组件,然后将Object.entries的键(category)和值(items)作为props传递给TreeNode组件。
在TreeNode中,您可以根据是否有子节点递归渲染TreeNode组件。这里有相关资源。
此外,您只能为第一级添加样式。
我使用了一个名为level的prop,并将其默认设置为1,然后仅在级别为1时添加样式(出于简单起见,我使用了内联样式)。对于下一级,我通过将level prop增加1来实现。
以下是JavaScript代码的翻译部分:
const Tree = ({ data = [] }) => {
  return (
    <div className="d-tree">
      <ul className="d-flex d-tree-container flex-column">
        {Object.entries(data).map(([category, items]) => (
          <TreeNode
            key={category}
            node={{ label: category, children: items }}
          />
        ))}
      </ul>
    </div>
  );
};
const TreeNode = ({ node, level = 1 }) => {
  const [childVisible, setChildVisibility] = useState(false);
  const hasChild = node.children && node.children.length > 0;
  const nodeStyle = level === 1 ? { fontWeight: "bold", color: "red" } : {};
  return (
    <li className="d-tree-node border-0">
      <div className="d-flex" onClick={(e) => setChildVisibility((v) => !v)}>
        <div className="col d-tree-head" style={nodeStyle}>
          {node.label}
        </div>
      </div>
      {hasChild && childVisible && (
        <div className="d-tree-content">
          <ul className="d-flex d-tree-container flex-column">
            {node.children.map((item) => (
              <TreeNode key={item.key} node={item} level={level + 1} />
            )}
          </ul>
        </div>
      )}
    </li>
  );
};
我已为您提供了代码的翻译部分。如果您需要任何其他帮助,请随时告诉我。
英文:
you could write the Tree component like this and pass down the key (category) and the value (items) of Object.entries as props to TreeNode
const Tree = ({ data = [] }) => {
  return (
    <div className="d-tree">
      <ul className="d-flex d-tree-container flex-column">
        {Object.entries(data).map(([category, items]) => (
          <TreeNode
            key={category}
            node={{ label: category, children: items }}
          />
        ))}
      </ul>
    </div>
  );
};
In the TreeNode you can recursively render TreeNode components based on if it has children or not. Here is a resource on that.
Also you can add styles only to the first level.
I used a prop called level and defaulted it to 1, then I give styles only if the level is 1 (used inline styles for simplicity). For the next levels, I increment the level prop by 1.
const TreeNode = ({ node, level = 1 }) => {
  const [childVisible, setChildVisiblity] = useState(false);
  const hasChild = node.children && node.children.length > 0;
  const nodeStyle = level === 1 ? { fontWeight: "bold", color: "red" } : {};
  return (
    <li className="d-tree-node border-0">
      <div className="d-flex" onClick={(e) => setChildVisiblity((v) => !v)}>
        <div className="col d-tree-head" style={nodeStyle}>
          {node.label}
        </div>
      </div>
      {hasChild && childVisible && (
        <div className="d-tree-content">
          <ul className="d-flex d-tree-container flex-column">
            {node.children.map((item) => (
              <TreeNode key={item.key} node={item} level={level + 1} />
            ))}
          </ul>
        </div>
      )}
    </li>
  );
};
<!-- begin snippet: js hide: false console: true babel: true -->
<!-- language: lang-js -->
const data = {  "Category 1": [    {      key: "1",      label: "Applications",      children: [        {          key: "3",          label: "Browser",          children: [            {              key: "4",              label: "Mozilla",              children: []            },            {              key: "5",              label: "Firefox",              children: []            }          ]        }      ]   }  ],  "Category 2": [    {      key: "2",      label: "OS",      children: [        {          key: "6",          label: "Windows",          children: []        }      ]    }  ]};
const TreeNode = ({ node, level = 1 }) => {
const [childVisible, setChildVisiblity] = React.useState(false);
const hasChild = node.children && node.children.length > 0;
const nodeStyle = level === 1 ? { fontWeight: "bold", color: "red" } : {};
return (
<li className="d-tree-node border-0">
<div className="d-flex" onClick={(e) => setChildVisiblity((v) => !v)}>
{hasChild && (
<div
className={`d-inline d-tree-toggler ${
childVisible ? "active" : ""
}`}
>
{'>'}
</div>
)}
<div className="col d-tree-head" style={nodeStyle}>
{node.label}
</div>
</div>
{hasChild && childVisible && (
<div className="d-tree-content">
<ul className="d-flex d-tree-container flex-column">
{node.children.map((item) => (
<TreeNode key={item.key} node={item} level={level + 1} />
))}
</ul>
</div>
)}
</li>
);
};
const Tree = ({ data = [] }) => {
return (
<div className="d-tree">
<ul className="d-flex d-tree-container flex-column">
{Object.entries(data).map(([category, items]) => (
<TreeNode
key={category}
node={{ label: category, children: items }}
/>
))}
</ul>
</div>
);
};
const TreeList = () => {
return <Tree data={data} />;
};
ReactDOM.render(<TreeList />, document.querySelector('.app'));
<!-- language: lang-css -->
.d-tree-container {
list-style: none;
padding: 0;
}
.d-tree-node {
padding: 0.75rem 1.25rem;
}
.d-tree-toggler.active {
transform: rotate(45deg);
}
<!-- language: lang-html -->
<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 class='app'></div>
<!-- end snippet -->
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论