vue 遇到了一个奇怪的问题.jpg

2018-07-18 17:34:19 +08:00
 xiaome

今天遇到个比较奇怪的问题,导致了死循环,请教了一系列大佬之后最终判断为 vue 视图重绘了。 记录一下,也想请求一下各位大佬更好的解决方案, 这里感谢各位了。

贴上代码, 如果需要执行请注释

<html>
<head>
  <title>测试</title>
  <link href="https://cdn.bootcss.com/bootstrap/4.1.1/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
  <div id="app">
    <div class="alert alert-primary" v-for="item in datas">
      <ul v-for="month in item.months">
        <li>{{month.month}} - {{month.name}}</li>
        <!-- 循环方法 -->
        <li>{{lastMonthStaff(item)}}</li>
      </ul>
    </div>
  </div>
  <script src="https://cdn.bootcss.com/vue/2.5.17-beta.0/vue.min.js"></script>
  <script>
    var app = new Vue({
      el: '#app',
      data: {
        datas: [
          {
            title: 2018,
            months: [
              { month: 1, name: '12asds' },
              { month: 2, name: 'adsfsdf' },
              { month: 3, name: 'zcvzcv' },
              { month: 4, name: 'zvcc' },
              { month: 5, name: 'eqr124' },
              { month: 6, name: 'asdfsd' },
              { month: 7, name: 'dsafds' },
              { month: 8, name: 'adsfsdfv' },
              { month: 9, name: 'yiyu' },
              { month: 10, name: 'cxvcxv' },
            ]
          },
          {
            title: 2019,
            months: [
              { month: 1, name: 'uteye' },
              { month: 2, name: 'dfgh' },
              { month: 3, name: 'AF' },
              { month: 4, name: 'FAGSGH' },
              { month: 5, name: 'DSGS' },
              { month: 6, name: '' },
              { month: 7, name: 'SFDG' },
              { month: 8, name: 'DSFG' },
              { month: 9, name: 'SDFG' },
              { month: 10, name: 'FDHDG' },
            ]
          },
          {
            title: 2020,
            months: [
              { month: 1, name: 'FGHGF' },
              { month: 2, name: 'FGH' },
              { month: 3, name: 'FDH' },
              { month: 4, name: 'FGHCVN' },
              { month: 5, name: 'BVCN' },
              { month: 6, name: '' },
              { month: 7, name: 'UIY' },
              { month: 8, name: 'DSHFM' },
              { month: 9, name: 'FSD' },
              { month: 10, name: 'DFSFDG' },
            ]
          },
        ],
        allotUsers: []
      },
      methods: {
        isShow(val) {
          switch (val) {
            case undefined:
              return false
            case '':
              return false
            case null:
              return false
            default:
              return true
          }
        },
        lastMonthStaff (row) {
          for (var obj of row.months) {
            if (obj.month === new Date().getMonth()) {
              if (this.isShow(obj.name)) {
                // 触发方法
                this.setAllotUsers(obj.name)
                // 输出上月 name
                return obj.name
              } else {
                return '无'
              }
            }
          }
        },
        setAllotUsers(val) {
          console.log(val)
          // 会触发视图更新导致死循环
          this.allotUser.push(val)

          // 想的笨办法解决方案
          this.allotUsers[this.allotUsers.length] = val
        },
      }
    })
  </script>
</body>
</html>
2261 次点击
所在节点    Vue.js
10 条回复
noe132
2018-07-18 18:42:10 +08:00
vue 确实会在控制台报错 render loop.
你的 setAllotUsers 循环执行了 1000 多次后被 vue 叫停了。
setAllotUsers 会触发 render,render 会调用 lastMonthStaff,于是就死循环了。

设置数组的属性不会被 vue 监测到所以不会有问题。
你的 view 编译成的 render 函数中调用了 lastMonthStaff,
lastMonthStaff 调用了 setAllotUsers
setAllotUsers 调用了 allotUsers,被 vue 感觉到了(对,跟踪你的依赖)
让 vue 以为 allotUsers 的更改会对 view 造成变化,需要重新 render,于是重新 render 又造成了属性变化。

我的建议是,数据的处理,放在 view 渲染之前。不要再 view 里添加修改数据的代码,这样会让逻辑变得不够清晰。因为 render 函数并不是你调用的,你不清楚具体什么时候 render 函数会被调用。render 函数应该是无副作用的。

具体 vue 是怎么跟踪依赖的,这还要翻翻 vue 的源码才知道了
xiaochocking
2018-07-18 18:46:05 +08:00
在 template 里调用函数修改数据本来就是不对的
chairuosen
2018-07-18 18:50:42 +08:00
在 get 里不要 set,在 render 里只调 get
luoway
2018-07-18 19:24:54 +08:00
v2ex 帖子不能删,过一年楼主回来看这个 isShow 会感到羞愧的
ioc
2018-07-18 19:31:50 +08:00
@luoway 可以删的
panyanyany
2018-07-18 22:03:47 +08:00
@luoway #4 你不说还没注意到,这个 isShow 确实有点意思……
billyu
2018-07-19 06:49:16 +08:00
@panyanyany hh break 被吃了
yinjunjian0
2018-07-19 10:14:30 +08:00
isShow 有丶东西
dengshen
2018-08-22 09:37:29 +08:00
@billyu 已经 return 没必要在写 break 了 如果用了标准 eslint 的话写 break 反而会报错
billyu
2018-08-22 09:47:09 +08:00
@dengshen #9 嗯嗯 是的 多谢提醒

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/472061

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX