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

为Ant Design树形表格数据的父级与子级添加唯一key并简化代码

问题描述

我已经把API返回的数据转换为适配Ant Design树形表格的格式,但目前遇到新问题:需要为每个父级和子级节点添加唯一的key,否则树形表格在展开/折叠时会重复生成行(注:只要key在所有父级和子级中唯一即可)。

恳请指导如何为父级和子级节点添加key,若能同时简化当前冗长的数据转换代码则更为感激。


当前数据转换代码

//api called data
let apiData = [
  {
    email: "alyssayo@xxx.com",
    permissionIds: null,
    roleIds: ["raa", "baa", "caa"],
    projectIds: ["1aa", "3aa"]
  },
  {
    email: "chiuewww@xxx.com",
    permissionIds: null,
    roleIds: ["baa", "caa"],
    projectIds: ["1aa", "2aa", "3aa"]
  },
  {
    email: "lalaqq@xxx.com",
    permissionIds: null,
    roleIds: ["caa"],
    projectIds: ["1aa"]
  }
];

//isolate and transform data
const data = apiData.reduce((arr, item) => {
    console.log("~~~arr",JSON.stringify(arr));
    console.log("~~~item",JSON.stringify(item));
  let formatted = item.projectIds.map((id) => {
    return {
      projectIds: id,
      children: [{ ...item, projectIds: id }]
    };
  });
  console.log("~~~formatted",JSON.stringify(formatted));
  console.log("arr Formtd", [...arr, ...formatted]);

  return [...arr, ...formatted];
}, []);



//Function to group the data
const findMatch = (arr, projectIds) => 
    arr.find(item => item.projectIds === projectIds)

const grouppingArray = (originalArr) => {
  return Array.isArray(originalArr) ? originalArr.reduce((previousObj, obj) => {
    if (findMatch(previousObj, obj.projectIds)) {
      findMatch(previousObj, obj.projectIds).children.push(...obj.children)
    } else {
      previousObj.push(obj)
    }
    return previousObj
  }, []) : 'Need an array'
}

console.log("FINALLL",JSON.stringify(grouppingArray(data)));

转换后的数据

[
  {
    "projectIds": "1aa",
    "children": [
      {
        "email": "alyssayo@xxx.com",
        "permissionIds": null,
        "roleIds": [
          "raa",
          "baa",
          "caa"
        ],
        "projectIds": "1aa"
      },
      {
        "email": "chiuewww@xxx.com",
        "permissionIds": null,
        "roleIds": [
          "baa",
          "caa"
        ],
        "projectIds": "1aa"
      },
      {
        "email": "lalaqq@xxx.com",
        "permissionIds": null,
        "roleIds": [
          "caa"
        ],
        "projectIds": "1aa"
      }
    ]
  },
  {
    "projectIds": "3aa",
    "children": [
      {
        "email": "alyssayo@xxx.com",
        "permissionIds": null,
        "roleIds": [
          "raa",
          "baa",
          "caa"
        ],
        "projectIds": "3aa"
      },
      {
        "email": "chiuewww@xxx.com",
        "permissionIds": null,
        "roleIds": [
          "baa",
          "caa"
        ],
        "projectIds": "3aa"
      }
    ]
  },
  {
    "projectIds": "2aa",
    "children": [
      {
        "email": "chiuewww@xxx.com",
        "permissionIds": null,
        "roleIds": [
          "baa",
          "caa"
        ],
        "projectIds": "2aa"
      }
    ]
  }
]

期望结果

[
  {
    "key": 1,
    "projectIds": "1aa",
    "children": [
      {
        "key": 2,
        "email": "alyssayo@xxx.com",
        "permissionIds": null,
        "roleIds": [
          "raa",
          "baa",
          "caa"
        ],
        "projectIds": "1aa"
      },
      {
        "key": 3,
        "email": "chiuewww@xxx.com",
        "permissionIds": null,
        "roleIds": [
          "baa",
          "caa"
        ],
        "projectIds": "1aa"
      },
      {
        "key": 4,
        "email": "lalaqq@xxx.com",
        "permissionIds": null,
        "roleIds": [
          "caa"
        ],
        "projectIds": "1aa"
      }
    ]
  },
  {
    "key": 5,
    "projectIds": "3aa",
    "children": [
      {
        "key": 6,
        "email": "alyssayo@xxx.com",
        "permissionIds": null,
        "roleIds": [
          "raa",
          "baa",
          "caa"
        ],
        "projectIds": "3aa"
      },
      {
        "key": 7,
        "email": "chiuewww@xxx.com",
        "permissionIds": null,
        "roleIds": [
          "baa",
          "caa"
        ],
        "projectIds": "3aa"
      }
    ]
  },
  {
    "key": 8,
    "projectIds": "2aa",
    "children": [
      {
        "key": 9,
        "email": "chiuewww@xxx.com",
        "permissionIds": null,
        "roleIds": [
          "baa",
          "caa"
        ],
        "projectIds": "2aa"
      }
    ]
  }
]

解决方案

可以通过先按projectId分组,再统一生成唯一key的方式实现,既简化代码逻辑,又保证key全局唯一:

let apiData = [
  { email: "alyssayo@xxx.com", permissionIds: null, roleIds: ["raa", "baa", "caa"], projectIds: ["1aa", "3aa"] },
  { email: "chiuewww@xxx.com", permissionIds: null, roleIds: ["baa", "caa"], projectIds: ["1aa", "2aa", "3aa"] },
  { email: "lalaqq@xxx.com", permissionIds: null, roleIds: ["caa"], projectIds: ["1aa"] }
];

// 第一步:按projectId分组,构建树形结构雏形
const projectGroups = apiData.reduce((groups, user) => {
  user.projectIds.forEach(projectId => {
    if (!groups[projectId]) groups[projectId] = [];
    groups[projectId].push({ ...user, projectIds: projectId });
  });
  return groups;
}, {});

// 第二步:生成带唯一key的最终树形数据
let keyCounter = 1;
const finalTreeData = Object.entries(projectGroups).map(([projectId, children]) => {
  const parentKey = keyCounter++;
  const childrenWithKeys = children.map(child => ({ ...child, key: keyCounter++ }));
  return { key: parentKey, projectIds: projectId, children: childrenWithKeys };
});

console.log(JSON.stringify(finalTreeData, null, 2));

代码说明

  1. 简化分组逻辑:直接用对象按projectId分组,避免原代码中拆分再合并的冗余步骤,执行效率更高。
  2. 全局唯一key:通过计数器keyCounter依次给父节点、子节点分配key,确保所有节点的key不重复。
  3. 逻辑清晰:分两步完成转换,先处理数据分组,再添加key,代码结构简洁易维护。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 04:50:30