You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React实现父子层级数据点击展开:子节点无法显示子项求助

问题分析与解决方案

你的代码无法展开嵌套子节点(比如id=2的节点),核心问题出在convertToTree函数的树形结构转换逻辑上:当前实现仅将顶层父节点(parent=null)存放在tree对象的根层级,子节点仅作为顶层节点的children元素存在,没有在全局节点映射中建立独立引用。当处理更深层的子节点(比如id=3,parent=2)时,找不到对应的父节点引用,导致该父节点的children数组始终为空。

修正后的代码实现

1. 正确的树形结构转换函数

function convertToTree(data: any) {
  // 建立所有节点的映射表,确保每个节点都有独立引用和初始化的children数组
  const nodeMap: Record<string, any> = {};
  data.forEach(item => {
    nodeMap[item.id] = { ...item, children: [] };
  });

  // 构建完整树形结构
  const treeRoots: any[] = [];
  data.forEach(item => {
    if (item.parent === null) {
      // 顶层节点直接加入根数组
      treeRoots.push(nodeMap[item.id]);
    } else {
      // 将子节点挂载到对应父节点的children中
      nodeMap[item.parent].children.push(nodeMap[item.id]);
    }
  });

  return treeRoots;
}

2. 保持TreeNode组件不变

function TreeNode({ data }: any) {
  const [isVisible, setIsVisible] = useState(false);

  const handleClick = () => {
    setIsVisible(!isVisible);
  };

  return (
    <div>
      <p onClick={handleClick}>{data.text}</p>
      {isVisible && data.children && data.children.length > 0 && (
        <ul>
          {data.children.map((child: any) => (
            <li key={child.id}>
              <TreeNode data={child} />
            </li>
          ))}
        </ul>
      )}
    </div>
  );
}

3. 父组件中使用方式

const data = [
  { id: 1, text: 'hello', parent: null },
  { id: 2, text: 'hello2', parent: 1 },
  { id: 3, text: 'hello3', parent: 2 },
  { id: 4, text: 'where are u?', parent: null },
];

const treeData = convertToTree(data);

// 渲染树形结构
return (
  <div>
    {treeData.map(node => (
      <TreeNode key={node.id} data={node} />
    ))}
  </div>
);

逻辑说明

  • 先通过nodeMap为每个节点创建独立引用,确保后续操作的是同一个节点对象。
  • 遍历数据时,将子节点准确挂载到其父节点的children数组中,保证整个树形结构的层级关联性。
  • 最终返回顶层节点数组,直接遍历渲染即可实现多层级的展开/折叠功能。

内容的提问来源于stack exchange,提问作者hasangkz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 04:08:04