如何在React中迭代渲染分类树结构?
迭代方式渲染React分类树结构
核心思路
不用递归,改用**栈(Stack)**遍历树结构,逐个生成React元素。栈中每个元素保存当前节点和对应的层级信息(用于控制嵌套缩进),通过循环处理栈内元素,将子节点依次压入栈完成全量遍历,彻底避免递归带来的内存问题。
完整实现代码
第一步:优化树结构转换(无副作用版本)
先把你的转树逻辑改成不修改原数组的版本,避免意外副作用:
const flat = [ { id: 1, parentId: 3 }, { id: 3, parentId: 8 }, { id: 4, parentId: 6 }, { id: 6, parentId: 3 }, { id: 7, parentId: 6 }, { id: 8, parentId: null }, { id: 16, parentId: null }, { id: 10, parentId: 8 }, { id: 15, parentId: 8 }, { id: 13, parentId: 14 }, { id: 14, parentId: 10 }, ]; const buildTree = (nodes: Array<{id: number, parentId: number | null}>) => { const nodeMap = new Map(); const rootNodes: any[] = []; // 先把所有节点存入Map,初始化children数组 nodes.forEach(node => { nodeMap.set(node.id, {...node, children: []}); }); // 关联父节点与子节点 nodes.forEach(node => { if (node.parentId === null) { rootNodes.push(nodeMap.get(node.id)); } else { const parentNode = nodeMap.get(node.parentId); parentNode?.children.push(nodeMap.get(node.id)); } }); return rootNodes; }; const treeRoot = buildTree(flat);
第二步:迭代渲染React组件
用栈遍历生成所有JSX元素,配合层级控制样式缩进:
import React from 'react'; const CategoryTree = () => { const treeRoot = buildTree(flat); const renderTreeIteratively = (root: any[]) => { const elements: React.ReactNode[] = []; // 栈元素格式:{ node: 节点对象, depth: 层级深度 } const stack = root.map(node => ({ node, depth: 0 })); while (stack.length > 0) { const { node, depth } = stack.pop()!; // 生成当前节点的JSX,用depth控制缩进 elements.push( <div key={node.id} style={{ marginLeft: `${depth * 20}px`, padding: '4px 0', cursor: 'pointer' }} > {node.id} {/* 替换为实际业务需要展示的内容 */} </div> ); // 子节点逆序压入栈,保证渲染顺序与原数组一致(栈是后进先出) if (node.children?.length) { for (let i = node.children.length - 1; i >= 0; i--) { stack.push({ node: node.children[i], depth: depth + 1 }); } } } return elements; }; return <div>{renderTreeIteratively(treeRoot)}</div>; }; export default CategoryTree;
关键细节说明
- 栈遍历逻辑:每次弹出栈顶节点生成元素,再逆序压入子节点——利用栈后进先出的特性,保证子节点按原顺序渲染。
- 层级样式控制:通过
depth计算marginLeft实现嵌套缩进,匹配你预期的层级展示效果。 - 内存友好:迭代方式不会产生递归调用栈溢出,适合处理大规模、深层级的树结构。
- 可扩展性:如果需要展开/折叠功能,可在栈元素中增加
isExpanded状态,或用额外Map记录节点展开状态,修改渲染逻辑即可。
内容的提问来源于stack exchange,提问作者Mantas Petrauskas
相关产品推荐
相关产品推荐

