如何将后端权限数据按分组渲染,实现单标题下多选框聚合展示
权限分组渲染解决方案
问题场景
从后端拿到的权限数据包含group字段(部分数据可能没有),当前循环渲染时每个权限项都会重复显示分组名称,需要实现每个分组只显示一次标题,下方聚合展示该组所有权限复选框的效果。
后端返回数据示例
[ { id: 54, name: "agent_read_all", description: null, displayName: "Read all", group: "Admin - Agent", }, { id: 55, name: "agent_read", description: "Fetch single record", displayName: "Read", }, { id: 56, name: "agent_create", description: null, displayName: "Create", group: "Admin - Agent", }, { id: 57, name: "agent_update", description: null, displayName: "Update", group: "Admin - Agent", }, { id: 62, name: "candidate_upload_batch_read_all", description: null, displayName: "Read all", }, ];
当前问题代码
<b>Permissions Section</b>; { Object.keys(permissions).map((item, index) => ( <> <List style={{ display: "flex" }}> <p>{permissions[item].group}</p> <FormGroup> <FormControlLabel control={ <Checkbox checked={uroleData.permissions[index] ? true : false} value={roleData.permissionId} onChange={(e) => { if (e.target.checked) { checkedp.push(permissions[item].id); setRoleData({ ...roleData, permissionId: checkedp }); } else { roleData.permissionId.splice( checkedp.indexOf(e.target.value), 1 ); } // console.log(roleData); }} /> } label={permissions[item].displayName} /> </FormGroup> </List> </> )); }
解决步骤
1. 先对权限数据按分组聚合
用Array.reduce()把原始数据转换成以分组名为键,对应权限数组为值的对象,没有group字段的项统一归到「未分组权限」组:
// 处理权限数据,按group分组 const groupedPermissions = permissions.reduce((acc, permission) => { // 给无group的项分配默认分组名 const groupName = permission.group || "未分组权限"; if (!acc[groupName]) { acc[groupName] = []; } acc[groupName].push(permission); return acc; }, {});
2. 修改渲染逻辑
循环分组后的对象,每个分组先渲染标题,再循环该组内的权限项渲染复选框。同时修正选中状态判断和勾选逻辑(原来的index判断不可靠,改成按权限ID匹配):
<b>Permissions Section</b> {/* 循环分组后的权限数据 */} {Object.entries(groupedPermissions).map(([groupName, permissionsInGroup]) => ( <div key={groupName}> {/* 渲染分组标题 */} <h4>{groupName}</h4> {/* 渲染当前分组下的所有权限复选框 */} {permissionsInGroup.map((permission) => { // 判断当前权限是否被选中 const isChecked = roleData.permissionId.includes(permission.id); return ( <List style={{ display: "flex" }} key={permission.id}> <FormGroup> <FormControlLabel control={ <Checkbox checked={isChecked} value={permission.id} onChange={(e) => { let updatedPermissions; if (e.target.checked) { // 勾选时添加权限ID updatedPermissions = [...roleData.permissionId, permission.id]; } else { // 取消勾选时移除权限ID updatedPermissions = roleData.permissionId.filter(id => id !== permission.id); } setRoleData({ ...roleData, permissionId: updatedPermissions }); }} /> } label={permission.displayName} /> </FormGroup> </List> ); })} </div> ))}
关键优化点
- 用
reduce聚合数据,避免重复渲染分组标题 - 选中状态改为通过权限ID判断,不再依赖数组索引,避免数据排序变化导致的错误
- 勾选逻辑采用不可变更新方式(扩展运算符、filter),避免直接修改state数组引发的问题
内容的提问来源于stack exchange,提问作者Navnath kumbhar
相关产品推荐
相关产品推荐

