Представление дерева пользовательского интерфейса материала, проверьте, есть ли у узла, на который я нажимаю, дочерние элементы

#reactjs #material-ui #treeview

Вопрос:

поэтому я пытаюсь создать дерево, используя представление дерева в пользовательском интерфейсе Material ( https://material-ui.com/components/tree-view/). Мы можем взять пример с их страницы:

 const data = {
  id: 'root',
  name: 'Parent',
  children: [
    {
      id: '1',
      name: 'Child - 1',
    },
    {
      id: '3',
      name: 'Child - 3',
      children: [
        {
          id: '4',
          name: 'Child - 4',
        },
      ],
    },
  ],
};

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

export default function RecursiveTreeView() {
  const classes = useStyles();

  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 (
    <TreeView
      className={classes.root}
      defaultCollapseIcon={<ExpandMoreIcon />}
      defaultExpanded={['root']}
      defaultExpandIcon={<ChevronRightIcon />}
    >
      {renderTree(data)}
    </TreeView>
  );
}
 

Что я хочу сделать, так это всякий раз, когда я нажимаю на узел, запускать какую-либо функцию, только если это конечный узел. Реквизит «onNodeSelect», который есть в treeview, дает мне только идентификатор узла, но не любую другую информацию об узле. Я знаю, что один из способов состоит в том, чтобы найти исходный json для этого идентификатора и найти узел, а затем проверить, есть ли у него дети, но мой json довольно большой, и я бы не хотел этого делать. Как-нибудь по-другому?

Ответ №1:

Потенциально вы можете использовать щелчок по ярлыку компонента TreeItem и отключить часть «выбор» в представлении дерева (например, использовать отключение выбора в представлении дерева).

Тогда ваш код может стать

 const handleTreeItemClick = (node) => {
  if( node.children amp;amp; node.children.length ) {
    // do some stuff
  } else {
    // do something else
  }  
}

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

В противном случае вы могли бы создать хэш данных с идентификаторами, указывающими на узел данных (не уверены в производительности хэширования большого объекта json?), а затем просто искать значение из хэша, а не искать каждый раз. Раздражает, я знаю, например.

 // do this outside of the render, perhaps in a redux selector or reducer
const hashMethod = (nodes, hash = {}) => {
  return nodes.reduce((h, node) => {
    h[node.id] = node;
    if( node.children) {
      h = hashMethod(node.children, h);
    }  
    return h;
  }, hash);
}

// sorry turned it into an array first so I can use reduce easier
const hashedData = hashMethod([data]); 
 

Затем в обработчике onNodeSelect внутри компонента (для одного выбора)

 const handleNodeSelect = (nodeId) => {
  const node = hashedData(nodeId);
  // do what you need with the data
}