skip to Main Content

I am trying to create a treeview in React.js. But I am not able to set it properly. Below is my code

App.js

import React from "react";
import TreeHierarchy from "./TreeHierarchy"; // Adjust path if necessary

const App = () => {
return (
<div style={{ padding: "20px" }}>
  <h1>Bahria Hierarchy</h1>
  <TreeHierarchy />
</div>
);
};

export default App;

TreeHierarchy.js

import React from "react";
import { TreeView, TreeItem } from "@mui/x-tree-view";
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
import ChevronRightIcon from "@mui/icons-material/ChevronRight";

// Sample hierarchy
const hierarchy = {
name: "Bahria",
precincts: [
{
  name: "Precinct-1",
  streets: [
    {
      name: "Road 1",
      meters: ["3092000001", "3092000210"],
    },
    {
      name: "Street 21",
      meters: ["3092000012"],
    },
    ],
    },
    ],
 };

// Recursive function to render the hierarchy tree
const TreeHierarchy = () => {
const renderTree = (node, parentId = "") => {
const nodeId = `${parentId}-${node.name || "node"}`;

return (
  <TreeItem key={nodeId} nodeId={nodeId} label={node.name || "Unnamed"}>
    {node.streets &&
      node.streets.map((street, index) =>
        renderTree(street, `${nodeId}-street-${index}`)
      )}
    {node.precincts &&
      node.precincts.map((precinct, index) =>
        renderTree(precinct, `${nodeId}-precinct-${index}`)
      )}
    {node.meters &&
      node.meters.map((meter, index) => (
        <TreeItem
          key={`${nodeId}-meter-${index}`}
          nodeId={`${nodeId}-meter-${index}`}
          label={`Meter: ${meter}`}
        />
      ))}
  </TreeItem>
);
};

return (
<TreeView
  defaultCollapseIcon={<ExpandMoreIcon />}
  defaultExpandIcon={<ChevronRightIcon />}
>
  {renderTree(hierarchy)}
</TreeView>
);
};

export default TreeHierarchy;

Output

enter image description here

When I click on the main node name I am getting below errors

MUI X: The Tree View component requires all items to have a unique `id` property.
Alternatively, you can use the `getItemId` prop to specify a custom id for each item.
Two items were provided with the same id in the `items` prop: "undefined"
Error: MUI X: The Tree View component requires all items to have a unique `id` property.
Alternatively, you can use the `getItemId` prop to specify a custom id for each item.
Two items were provided with the same id in the `items` prop: "undefined"
at http://localhost:3000/static/js/bundle.js:15169:15
at basicStateReducer (http://localhost:3000/static/js/bundle.js:37272:45)
at updateReducer (http://localhost:3000/static/js/bundle.js:37381:26)
at updateState (http://localhost:3000/static/js/bundle.js:37667:14)
at Object.useState (http://localhost:3000/static/js/bundle.js:38464:20)
at Object.useState (http://localhost:3000/static/js/bundle.js:54836:25)
at useTreeView (http://localhost:3000/static/js/bundle.js:16177:64)
at SimpleTreeView (http://localhost:3000/static/js/bundle.js:12473:83)
at renderWithHooks (http://localhost:3000/static/js/bundle.js:37072:22)
at updateForwardRef (http://localhost:3000/static/js/bundle.js:40321:24)

The tree structure is below

Bharia (Parent node)
  => Precinct (value)
      =>streets (value)
         => meters (value)

I am stuck to it and must be missing something. Any help would be highly appreciated.

2

Answers


  1. Each TreeItem needs a unique itemId

    … as stated in the documentation.

    This is the changed renderTree function that respects this requirement:

    const renderTree = (node, parentId = "") => {
      const nodeId = `${parentId}-${node.name || "node"}`;
    
      return (
        <TreeItem
          key={nodeId}
          // itemId added here
          itemId={nodeId}
          nodeId={nodeId}
          label={node.name || "Unnamed"}
        >
          {node.streets &&
            node.streets.map((street, index) =>
              renderTree(street, `${nodeId}-street-${index}`)
            )}
          {node.precincts &&
            node.precincts.map((precinct, index) =>
              renderTree(precinct, `${nodeId}-precinct-${index}`)
            )}
          {node.meters &&
            node.meters.map((meter, index) => {
              // an `id` constant to avoid repeating code
              const id = `${nodeId}-meter-${index}`;
              return (
                <TreeItem
                  key={id}
                  // ...and another itemId here
                  itemId={id}
                  nodeId={`${nodeId}-meter-${index}`}
                  label={`Meter: ${meter}`}
                />
              );
            })}
        </TreeItem>
      );
    };
    

    In the code above, I’ve added a unique itemId property to each TreeItem.
    I’ve also added an id constant in your node.meters.map(...) function argument, to avoid repeating the template string literal.

    Login or Signup to reply.
  2. Ill give you simple start

    export interface Tree {
      id?: number;
      name: string;
      parentId?: number | null;
      parent?: Tree;
      children: Array<Tree>;
    }
    
    const TreeView = ({ data }: { data: Tree[] }) => {
      return (
        <ul style={{ marginLeft: 10 }}>
          {data.map((f) => {
            return (
              <li key={`li-${f.id}`} style={{ marginLeft: "25px", marginTop: "10px" }}>
                <p style={{ display: "flex" }}>
                  <span style={{ marginLeft: "15px", paddingTop: 5 }}>{f.name}</span>
                </p>
                {f.children && <TreeView data={f.children} />}
              </li>
            );
          })}
        </ul>
      );
    };
    export default TreeView;
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search