ReactJS and Material UI TreeView: can I use a JSON/array of object to populate the TreeView?

ReactJS and Material UI TreeView: can I use a JSON/array of object to populate the TreeView?

The TreeView component doesnt have anything built-in for this, but it is fairly straightforward to create re-usable code to provide this functionality for a given data structure.

Here is one way to do it:

import React from react;
import ReactDOM from react-dom;

import TreeView from @material-ui/lab/TreeView;
import TreeItem from @material-ui/lab/TreeItem;
import ExpandMoreIcon from @material-ui/icons/ExpandMore;
import ChevronRightIcon from @material-ui/icons/ChevronRight;
import { sampleFromStackOverflowQuestion, seasons } from ./sampleData;

const getTreeItemsFromData = treeItems => {
  return treeItems.map(treeItemData => {
    let children = undefined;
    if (treeItemData.children && treeItemData.children.length > 0) {
      children = getTreeItemsFromData(treeItemData.children);
    }
    return (
      <TreeItem
        key={treeItemData.id}
        nodeId={treeItemData.id}
        label={treeItemData.name}
        children={children}
      />
    );
  });
};
const DataTreeView = ({ treeItems }) => {
  return (
    <TreeView
      defaultCollapseIcon={<ExpandMoreIcon />}
      defaultExpandIcon={<ChevronRightIcon />}
    >
      {getTreeItemsFromData(treeItems)}
    </TreeView>
  );
};

function App() {
  return (
    <div className=App>
      <DataTreeView treeItems={sampleFromStackOverflowQuestion} />
      <br />
      <DataTreeView treeItems={seasons} />
    </div>
  );
}

const rootElement = document.getElementById(root);
ReactDOM.render(<App />, rootElement);

Edit

DataTreeView and getTreeItemsFromData could be moved into a separate file and then imported in order to reuse them in multiple components.

Here is a Typescript version:

import * as React from react;

import TreeView from @material-ui/lab/TreeView;
import TreeItem from @material-ui/lab/TreeItem;
import ExpandMoreIcon from @material-ui/icons/ExpandMore;
import ChevronRightIcon from @material-ui/icons/ChevronRight;
import {
  sampleFromStackOverflowQuestion,
  seasons,
  TreeItemData
} from ./sampleData;

const getTreeItemsFromData = (treeItems: TreeItemData[]) => {
  return treeItems.map(treeItemData => {
    let children = undefined;
    if (treeItemData.children && treeItemData.children.length > 0) {
      children = getTreeItemsFromData(treeItemData.children);
    }
    return (
      <TreeItem
        key={treeItemData.id}
        nodeId={treeItemData.id}
        label={treeItemData.name}
        children={children}
      />
    );
  });
};
interface DataTreeViewProps {
  treeItems: TreeItemData[];
}
function DataTreeView({ treeItems }: DataTreeViewProps) {
  return (
    <TreeView
      defaultCollapseIcon={<ExpandMoreIcon />}
      defaultExpandIcon={<ChevronRightIcon />}
    >
      {getTreeItemsFromData(treeItems)}
    </TreeView>
  );
}

export default function App() {
  return (
    <div className=App>
      <DataTreeView treeItems={sampleFromStackOverflowQuestion} />
      <br />
      <DataTreeView treeItems={seasons} />
    </div>
  );
}

Edit

Here is one more way to day as mentioned in the Material UI Docs.

import React from react;
import { makeStyles } from @material-ui/core/styles;
import TreeView from @material-ui/lab/TreeView;
import ExpandMoreIcon from @material-ui/icons/ExpandMore;
import ChevronRightIcon from @material-ui/icons/ChevronRight;
import TreeItem from @material-ui/lab/TreeItem;
import _ from lodash;

const useStyles = makeStyles({
  root: {
    height: 216,
    flexGrow: 1,
    maxWidth: 400,
  },
});

export default function ControlledTreeView(props) {
  const classes = useStyles();
  const [expanded, setExpanded] = React.useState([]);
  const [selected, setSelected] = React.useState([]);
  const [searchValue, setSearchValue] = React.useState();
  const [stateData, setStateData] = React.useState([]);

  React.useEffect(
    () => {
      const { data } = props;
      setStateData(data);
    },
    [props],
  );

  const handleToggle = (event, nodeIds) => {
    setExpanded(nodeIds);
  };

  const handleSelect = (event, nodeIds) => {
    setSelected(nodeIds);
  };

  const onSearch = (search) => {
    setSearchValue(search);
    console.log(searchTree(search, props.data));
  };

  function searchTree(str, data) {
    const searchStr = str.toLowerCase();

    // Only return the entries that contain a matched value
    return _.filter(data, (datum) => {
      // Check if name matches
      return _.includes(datum.name, searchStr)
      || _.some(datum.activities, (activity) => {
          return _.entries(activity.routines).some(([routine, {details}]) => {
            // Check if dynamic routine matches or details
            return _.includes(routine, searchStr) || _.includes(details, searchStr);
          });
        });
    });
  };

  const renderTree = (nodes) => (
    <TreeItem key={nodes.id} nodeId={nodes.id} label={nodes.name}>
      {Array.isArray(nodes.children) ? nodes.children.map((node) => renderTree(node)) : null}
    </TreeItem>
  );

  return (
    <div>
      <TreeView
        className={classes.root}
        defaultCollapseIcon={<ExpandMoreIcon />}
        defaultExpanded={[root]}
        defaultExpandIcon={<ChevronRightIcon />}
      >
        {renderTree(stateData)}
      </TreeView>
    </div>
  );
}

And you can call this component as
<CustomizedTreeView data={TreeViewData} />

where your TreeViewData will be

const TreeViewData = {
  id: root,
  name: Documents,
  children: [
    {
      id: 1,
      name: Report,
      children: [
        {
          id: 2,
          name: PDF,
        },
      ],
    },
    {
      id: 3,
      name: Files,
      children: [
        {
          id: 4,
          name: Excel,
        },
      ],
    },
    {
      id: 5,
      name: Programs,
      children: [
        {
          id: 6,
          name: Codes,
        },
        {
          id: 7,
          name: Data,
        },
      ],
    },
  ],
};

ReactJS and Material UI TreeView: can I use a JSON/array of object to populate the TreeView?

Leave a Reply

Your email address will not be published.