javascriptreactjsmaterial-uimui-x-tree-view

Unable to create a tree view in reactjs


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.


Solution

  • 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.