JavaScript树形结构怎样实现递归渲染【教程】

发布时间 - 2026-01-21 00:00:00    点击率:
直接用 render 递归组件报 “Maximum update depth exceeded” 是因 props 引用不稳定导致无限重渲染;需用 useMemo 保证 data 稳定、避免内联函数、不触发副作用,并配合展开状态控制渲染时机。

为什么直接用 render 递归组件会报 “Maximum update depth exceeded”?

React 中用函数组件递归渲染树形结构时,常见错误是没控制好 props 变化,导致每次渲染都生成新对象或新数组,触发子组件无限重渲染。核心问题不在递归本身,而在 childrendata 属性的引用稳定性。

  • 避免在父组件内直接写 {data.children.map(...)} 并传入内联函数作为子项渲染逻辑
  • 确保传给子组件的 data 是稳定引用(比如来自 useMemo 或原始数据源)
  • 不要在递归组件内部调用 setState 或触发副作用(如 useEffect 无依赖数组)而意外引起重渲染

TreeItem 组件怎么写才支持多层嵌套且不卡顿?

关键不是“能递归”,而是“只在必要时递归”。建议用懒加载 + 展开状态控制子树是否挂载,而不是一次性渲染全部节点。

  • useState 管理每个节点的 expanded 状态,初始可设为 false
  • 只在 expanded === true 时才渲染 children,否则用占位符(如 "▶" 按钮)
  • 对深层嵌套加 shouldComponentUpdate 类似逻辑:用 React.memo 包裹 TreeItem,并确保 props 浅比较稳定
  • 若节点数超 500,考虑虚拟滚动(如 react-window),但注意它不原生支持嵌套结构,需自行 flatten 数据

如何让 TreeNode 支持点击折叠、拖拽排序、右键菜单?

这些交互能力必须和递归结构解耦——把行为逻辑提到父级或自定义 Hook 里,而不是塞进递归组件内部。

  • 折叠/展开统一由父组件管理一个 expandedKeys Set 或 Map,通过 onToggle 回调通知父级更新
  • 拖拽排序不要在 TreeItem 内处理 onDragStart,改用 HTML5 Drag and Drop APIdataTransfer.setData 存节点 key,再在目标位置 onDrop 时重组数据
  • 右键菜单推荐用 contextMenu 事件 + event.preventDefault(),配合绝对定位浮层;菜单项操作(如删除、新增)应触发父组件的 onContextMenuAction 回调,而非在子组件里直接修改 state

Vue 3 的 v-for 递归模板为什么总丢 key 或响应失效?

Vue 的递归组件必须显式命名,并在模板中用该名称调用自身;key 必须基于每个节点唯一标识(不能只用索引),且整个数据结构需是响应式的。

  • 组件名要和 name 选项一致,例如 name: 'TreeNode',模板里写
  • 如果数据来自

    API,用 refreactive 包裹,否则 node.children 变化不会触发更新
  • 避免在 v-for 中使用计算属性返回新数组(如 computed(() => data.filter(...))),这会导致 key 失效;应预处理好数据再传入
实际项目中最容易被忽略的是:树节点的唯一 key 设计。用随机 ID 或时间戳生成 key 会导致展开/收起状态丢失;用后端返回的 id 字段最稳妥,但要注意它是否真正全局唯一——尤其涉及跨层级拖拽合并时,重复 id 会让 Vue/React 的 diff 算法出错。


# vue  # react  # javascript  # java  # html  # node  # html5  # 懒加载  # 后端  # win  # 拖拽排序 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: HTML透明颜色代码怎么让图片透明_给img元素加透明色的技巧【方法】  Win11怎样安装网易有道词典_Win11安装词典教程【步骤】  如何用手机制作网站和网页,手机移动端的网站能制作成中英双语的吗?  大连网站制作费用,大连新青年网站,五年四班里的视频怎样下载啊?  JavaScript Ajax实现异步通信  Laravel如何实现模型的全局作用域?(Global Scope示例)  如何构建满足综合性能需求的优质建站方案?  Laravel用户密码怎么加密_Laravel Hash门面使用教程  长沙做网站要多少钱,长沙国安网络怎么样?  Android仿QQ列表左滑删除操作  PHP 500报错的快速解决方法  如何用PHP快速搭建CMS系统?  动图在线制作网站有哪些,滑动动图图集怎么做?  Laravel怎么多语言本地化设置_Laravel语言包翻译与Locale动态切换【手册】  在centOS 7安装mysql 5.7的详细教程  Java遍历集合的三种方式  JavaScript中如何操作剪贴板_ClipboardAPI怎么用  Android滚轮选择时间控件使用详解  高防服务器租用首荐平台,企业级优惠套餐快速部署  Laravel任务队列怎么用_Laravel Queues异步处理任务提升应用性能  如何自定义建站之星网站的导航菜单样式?  JS实现鼠标移上去显示图片或微信二维码  Laravel如何实现文件上传和存储?(本地与S3配置)  如何用y主机助手快速搭建网站?  如何在 Go 中优雅地映射具有动态字段的 JSON 对象到结构体  夸克浏览器网页跳转延迟怎么办 夸克浏览器跳转优化  如何在IIS中新建站点并解决端口绑定冲突?  Laravel如何实现数据导出到PDF_Laravel使用snappy生成网页快照PDF【方案】  Laravel如何实现数据库事务?(DB Facade示例)  香港代理服务器配置指南:高匿IP选择、跨境加速与SEO优化技巧  详解一款开源免费的.NET文档操作组件DocX(.NET组件介绍之一)  Win11怎么设置默认图片查看器_Windows11照片应用关联设置  如何自己制作一个网站链接,如何制作一个企业网站,建设网站的基本步骤有哪些?  如何在 Python 中将列表项按字母顺序编号(a.、b.、c. …)  Python正则表达式进阶教程_复杂匹配与分组替换解析  Laravel如何配置和使用缓存?(Redis代码示例)  企业在线网站设计制作流程,想建设一个属于自己的企业网站,该如何去做?  如何快速启动建站代理加盟业务?  如何用腾讯建站主机快速创建免费网站?  进行网站优化必须要坚持的四大原则  uc浏览器二维码扫描入口_uc浏览器扫码功能使用地址  Laravel如何配置Horizon来管理队列?(安装和使用)  如何在阿里云完成域名注册与建站?  如何在服务器上配置二级域名建站?  如何破解联通资金短缺导致的基站建设难题?  MySQL查询结果复制到新表的方法(更新、插入)  米侠浏览器网页背景异常怎么办 米侠显示修复  魔毅自助建站系统:模板定制与SEO优化一键生成指南  如何选择PHP开源工具快速搭建网站?  Edge浏览器如何截图和滚动截图_微软Edge网页捕获功能使用教程【技巧】