如何修改React代码生成合规的无键名嵌套侧边栏结构?
问题
需要从指定路径(示例:/docs/quick-start/messaging/Virtual-Numbers/digital/)生成用于侧边栏的嵌套文件夹结构,目前已实现功能但结果不符合预期。当前代码生成的是带键名的嵌套对象结构,想要生成以children数组存储子节点的层级结构。以下是相关代码、当前输出及合规的期望结构,请问如何修改代码?
原代码片段
export function useSideNavState() { const data = useStaticQuery(SideNavQuery) const tree = {} //Working Code newGroups.forEach(({ name: topNodeName, nodes }) => { let currentNode = tree nodes.forEach(({ fields }) => { const { slug, nodeName } = fields // /docs/quick-start/messaging/Virtual-Numbers/digital/ let parts = slug.split('/') parts = parts.filter((element) => { return element !== '' }) const lastPart = parts[parts.length - 2] parts.forEach((part, index) => { if (part === '') return currentNode[part] = currentNode[part] ?? {} currentNode[part].name = currentNode[part].name ?? part currentNode = currentNode[part] if (index === parts.length - 2) { currentNode.name = nodeName ?? lastPart } }) if (!currentNode.items) currentNode.items = [] currentNode.items.push(fields) currentNode = tree }) if (!tree[topNodeName]) tree[topNodeName] = {} tree[topNodeName][topNodeName] = { ...currentNode[topNodeName], name: topNodeName, } addNameProperty(tree[topNodeName]) }) // helper function to add name property recursively function addNameProperty(obj) { for (const key in obj) { if (typeof obj[key] === 'object') { obj[key].name = obj[key].name ?? key addNameProperty(obj[key]) } } } console.log(tree) return newGroups }) // console.log(navGroups) return { navGroups } }
当前输出
{ "name": "docs", "quick-start": { "name": "quick-start", "messaging": { "name": "messaging", "items": [ { "title": "Messaging", "pageType": "doc", "section": "messaging", "order": 1, "slug": "/docs/quick-start/messaging/" } ], "Virtual-Numbers": { "name": "Virtual-Numbers", "digital": { "name": "digital", "items": [ { "title": "digital", "pageType": "doc", "section": "messaging", "order": -9999, "slug": "/docs/quick-start/messaging/Virtual-Numbers/digital/" } ] }, "items": [ { "title": "EnableX Virtual Numbers", "pageType": "doc", "section": "messaging", "order": -9999, "slug": "/docs/quick-start/messaging/Virtual-Numbers" } ] } } } }
期望输出(合规格式)
{ "name": "docs", "children": [ { "name": "quick-start", "children": [ { "name": "messaging", "items": [ { "title": "Messaging", "pageType": "doc", "section": "messaging", "order": 1, "slug": "/docs/quick-start/messaging/" } ], "children": [ { "name": "Virtual-Numbers", "children": [ { "name": "digital", "items": [ { "title": "digital", "pageType": "doc", "section": "messaging", "order": -9999, "slug": "/docs/quick-start/messaging/Virtual-Numbers/digital/" } ] } ], "items": [ { "title": "EnableX Virtual Numbers", "pageType": "doc", "section": "messaging", "order": -9999, "slug": "/docs/quick-start/messaging/Virtual-Numbers" } ] } ] } ] } ] }
解决方案
核心改动是把原有的键值对嵌套对象改成**children数组存储子节点**的结构,具体修改如下:
修改后的完整代码
export function useSideNavState() { const data = useStaticQuery(SideNavQuery) // 初始化根节点,包含name和children数组 const tree = { name: "docs", children: [] }; newGroups.forEach(({ name: topNodeName, nodes }) => { let currentNode = tree; nodes.forEach(({ fields }) => { const { slug, nodeName } = fields; // 拆分路径并过滤空片段,移除末尾的空项(因路径带/) let parts = slug.split("/").filter(element => element !== ""); parts = parts.slice(0, -1); const lastPart = parts[parts.length - 1]; parts.forEach((part, index) => { // 在当前节点的children中查找已存在的节点 let existingNode = currentNode.children.find(child => child.name === part); if (!existingNode) { // 不存在则创建新节点,包含name和空children数组 existingNode = { name: part, children: [] }; currentNode.children.push(existingNode); } currentNode = existingNode; // 若为最后一个层级,替换为nodeName(如果有) if (index === parts.length - 1) { currentNode.name = nodeName ?? lastPart; } }); // 为当前节点添加items数组并推入字段 if (!currentNode.items) currentNode.items = []; currentNode.items.push(fields); // 重置回根节点 currentNode = tree; }); }); console.log(tree); // 返回处理后的树结构 return { navGroups: tree }; }
关键改动说明
- 根节点初始化:直接定义符合期望结构的根节点,包含
name和空children数组 - 节点查找与创建:遍历路径片段时,通过
children.find匹配已存在的子节点,不存在则创建新节点并推入数组 - 命名逻辑保留:保持原有的
nodeName优先级,无nodeName时使用路径片段名称 - 移除冗余函数:删除原
addNameProperty辅助函数,节点创建时已直接设置name属性
内容的提问来源于stack exchange,提问作者Guru Pawar
相关产品推荐
相关产品推荐

