Vue 响应式无限递归问题总结

Vue 响应式无限递归问题总结

问题现象

在项目中遇到了 "Maximum call stack size exceeded"(最大调用堆栈大小超出)错误,导致页面无法正常加载。

问题原因

1. 响应式对象的问题

  • Vue 的 Vuex 状态管理中的数据是响应式对象
  • 响应式对象包含特殊的 getter 和 setter,用于监听数据变化
  • 当访问响应式对象的属性时,会触发这些 getter

2. 循环引用导致无限递归

  • 在路由过滤函数中,直接访问 Vuex 中的菜单数据
  • 当访问 menu.menuType 时,触发 Vue 的响应式 getter
  • 由于某些原因(可能是数据结构或 Vue 版本问题),这个 getter 存在循环引用
  • 导致无限递归调用,最终堆栈溢出

3. 为什么之前能运行

  • 可能之前的菜单数据结构不同
  • 或者 Vue 的响应式系统配置有变化
  • 或者某个依赖更新导致了这个问题

解决方案

核心思路:移除响应式引用

使用 JSON 序列化和反序列化,将响应式对象转换为普通 JavaScript 对象:

javascript 复制代码
// 修改前(有问题)
function filterRoutesByMenus(routes, menus) {
  const pageMenuNames = [];
  const extractPageMenuNames = (menuList) => {
    menuList.forEach((menu) => {
      if (menu.menuType === "2") {  // 访问响应式对象,触发无限递归
        pageMenuNames.push(menu.name);
      }
      if (Array.isArray(menu.children) && menu.children.length > 0) {
        extractPageMenuNames(menu.children);
      }
    });
  };
  extractPageMenuNames(menus);  // 直接使用响应式对象
  // ...
}

// 修改后(正确)
function filterRoutesByMenus(routes, menus) {
  const pageMenuNames = [];
  // 使用 JSON 序列化移除响应式引用
  const safeMenus = JSON.parse(JSON.stringify(menus || []));
  const extractPageMenuNames = (menuList) => {
    menuList.forEach((menu) => {
      if (menu.menuType === "2") {  // 访问普通对象,不会触发递归
        pageMenuNames.push(menu.name);
      }
      if (Array.isArray(menu.children) && menu.children.length > 0) {
        extractPageMenuNames(menu.children);
      }
    });
  };
  extractPageMenuNames(safeMenus);  // 使用普通对象
  // ...
}

为什么这样解决有效

1. JSON 序列化的作用

  • JSON.stringify() 将对象转换为 JSON 字符串,移除所有响应式特性
  • JSON.parse() 将 JSON 字符串转换回普通 JavaScript 对象
  • 得到的对象是纯净的,没有任何 Vue 的响应式特性

2. 避免响应式触发

  • 普通对象的属性访问不会触发 Vue 的 getter
  • 不会存在循环引用问题
  • 代码可以正常执行,不会陷入无限递归

3. 保持功能不变

  • 菜单过滤逻辑完全相同
  • 只是改变了数据源的类型
  • 不影响业务逻辑

总结

核心问题:Vue 响应式对象在特定情况下会触发无限递归

解决方案:使用 JSON 序列化将响应式对象转换为普通对象

关键点

  • 响应式对象包含特殊的 getter/setter
  • 直接访问可能触发无限递归
  • JSON 序列化可以移除响应式特性
  • 普通对象不会触发 Vue 的响应式系统

这是一个常见的 Vue 响应式系统问题,通过移除响应式引用可以有效解决。

相关推荐
一切顺势而行2 小时前
python 文件目录操作
java·前端·python
014-code2 小时前
Vue3 性能优化实战
前端·vue.js·性能优化
强子感冒了3 小时前
JavaScript 零基础入门笔记:核心概念与语法详解
开发语言·javascript·笔记
css趣多多3 小时前
vue2项目改造为vue3遇到的问题以及解决办法
前端·vue.js·elementui
哆啦A梦15883 小时前
Vue3魔法手册 作者 张天禹 09_props的使用
前端·vue.js·typescript
哆啦A梦15883 小时前
Vue3魔法手册 作者 张天禹 11_自定义hooks
前端·vue.js·typescript
广州华水科技4 小时前
单北斗变形监测在大坝安全和地质灾害预警中的应用与优势
前端
一叶星殇4 小时前
Windows 下用 Nginx 部署 Vue + .NET WebApi 全流程实战
vue.js·windows·nginx
阿珊和她的猫4 小时前
深入理解 Vue 3 的 `setup` 函数
前端·vue.js·状态模式