为Ant Design表格新增多check属性实现默认选中行的技术问题
数据转换逻辑拆分与异步问题处理
当前基于Ant Design表格的选中行需求,已经实现了给getAllUserRole返回数据添加checkRole数组的逻辑,但现在要完成两个新需求:
- 针对
resProject数据源,先给每条数据添加key字段,再给用户角色数据新增checkProject属性 - 给
getAllUserRole的返回数据再加checkDept数组属性
如果把所有逻辑都堆在getDataUserRole里,代码会混乱不堪,还容易触发异步问题。先看原代码:
async function getDataProject() { let resProject = await getAllProject(); if (resProject) { setDataSourceProject(resProject.data); } } async function getDataUserRole() { let resRole = await getAllRoles(); if (resRole) { // 给每个角色添加key for (var i = 0; i < resRole.data.length; i++) { resRole.data[i]["key"] = i; } setDataSourceRole(resRole.data); let res = await getAllUserRole(); if (res) { console.log("getAllUserRole =", res); for (var i = 0; i < res.data.length; i++) { // 给每条用户数据添加checkRole数组 res.data[i]["checkRole"] = []; // 遍历当前用户的roleIds数组 for (var j = 0; j < res.data[i].roleIds.length; j++) { // 如果roleIds不为空 if (res.data[i].roleIds.length != 0) { // 遍历所有角色数据,匹配id后把角色的key推入checkRole for (var k = 0; k < resRole.data.length; k++) { if (res.data[i].roleIds[j] == resRole.data[k].id) { res.data[i]["checkRole"].push(resRole.data[k].key); } } } } } // 如果groupChange为空,直接设置未转换的数据 if (!(groupChange)) { setDataSourceUserRole(res.data); } // 如果groupChange有值,调用分组函数后设置数据 else { var treeData = groupData(res.data, groupChange) setDataSourceUserRole(treeData); } } } }
解决思路:拆分逻辑 + 优化异步
1. 抽离通用工具函数
把重复的加key、匹配选中项逻辑单独拎出来,复用性强且代码更整洁:
// 给数组每条数据添加key字段 function addKeyToData(data) { return data.map((item, idx) => ({ ...item, key: idx })); } // 根据关联数据生成选中的key数组(比如用角色id匹配角色的key) function getCheckedKeys(targetItem, relationList, targetIdKey, relationIdKey) { return relationList .filter(relationItem => targetItem[targetIdKey].includes(relationItem[relationIdKey])) .map(relationItem => relationItem.key); }
2. 重构getDataProject
直接在这个函数内完成项目数据的key添加:
async function getDataProject() { const resProject = await getAllProject(); if (resProject) { const projectWithKey = addKeyToData(resProject.data); setDataSourceProject(projectWithKey); } }
3. 彻底重构getDataUserRole
用Promise.all并行请求所有需要的接口,避免嵌套异步的等待问题,同时拆分三个check属性的生成逻辑:
async function getDataUserRole() { // 并行拉取角色、项目、用户角色数据,比串行请求效率更高 const [resRole, resProject, resUserRole] = await Promise.all([ getAllRoles(), getAllProject(), getAllUserRole() ]); // 任一请求失败则直接返回 if (!resRole || !resProject || !resUserRole) return; // 给角色、项目数据添加key const roleWithKey = addKeyToData(resRole.data); const projectWithKey = addKeyToData(resProject.data); setDataSourceRole(roleWithKey); setDataSourceProject(projectWithKey); // 处理用户角色数据的三个check属性 const transformedData = resUserRole.data.map((userItem, idx) => { return { ...userItem, key: idx, // 给用户数据也添加key,方便表格操作 checkRole: getCheckedKeys(userItem, roleWithKey, 'roleIds', 'id'), checkProject: getCheckedKeys(userItem, projectWithKey, 'projectIds', 'id'), // 假设用户数据包含projectIds字段,可按需修改 checkDept: [] // 替换为部门数据的匹配逻辑,格式和上面一致 }; }); // 处理分组逻辑 const finalData = groupChange ? groupData(transformedData, groupChange) : transformedData; setDataSourceUserRole(finalData); }
优化亮点
- 职责清晰:每个函数只负责单一功能,避免逻辑堆砌
- 异步安全:并行请求避免嵌套await的顺序问题,一次性获取所有依赖数据
- 无副作用:用
map和扩展运算符生成新数据,不直接修改接口返回的原始数据,减少意外bug
内容的提问来源于stack exchange,提问作者Jing c
相关产品推荐
相关产品推荐

