如何解决Vue警告:您可能在组件渲染函数中有一个无限更新循环

4

我收到了以下无限循环警告。 我明白这可能是因为我在模板的for循环中更改了一个变量,因为调用了一个方法。 有什么办法可以解决吗? 循环确实完成了,所以它实际上并不是一个无限循环,但我想修复警告。

[Vue warn]: You may have an infinite update loop in a component render function.

代码片段:

new Vue({
  el: '#app',
  data: {
    contents: {"34": {"id": 34, build_name: "email_simple", build_readable: "Email"},"35": {"id": 35, build_name: "email_complex", build_readable: "Email"},"36": {"id": 36, build_name: "email_half", build_readable: "Email"}},
    last_build_type: '',
    contents_tree: [34,35,36]
  }, 
  methods: {
      checkBuildType(id){
        let check = false;
        if(this.last_build_type !== this.contents[id].build_name){
            check = true
        }
        this.last_build_type = this.contents[id].build_name;
        return check
      }

  }
  
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
  <template v-for="(id, i) in contents_tree">
      <div v-bind:key="i + '_' + id" class="inline">
          <template v-if="checkBuildType(id)">
              {{i}} - {{id}} -
              {{contents[id].build_readable}}
              <br>
            
          </template>

    </div>
  </template>
</div>


contents_tree是什么?我认为我们需要更多的代码来查看实际上是什么导致了错误。 - depperm
请发布精确的错误信息。 - adiga
我已经添加了其余的代码。页面上还有更多的代码,但我已经将它们全部注释掉了,错误是从这里出现的。我添加了准确的错误信息。 - Jordan
1
很高兴能够帮忙,但请提供可运行的CodePen或其他完整的代码片段以重现错误。https://stackoverflow.com/help/minimal-reproducible-example - AlexMA
2
@AlexMA,我已经添加了产生错误的代码片段。 - Jordan
显示剩余5条评论
1个回答

4
您之所以收到该警告是因为Vue必须重新渲染v-for循环中的每个项目,由于循环更新了组件的状态。我的解决方案是在计算属性(基本上是一个索引对象)中一次性计算每个数组项的结果,并在v-for中访问该计算属性,而不是使用checkBuildType方法。

new Vue({
  el: '#app',
  data: {
    contents: {
      "33": {
        "id": 33,
        build_name: "email_half",
        build_readable: "Email"
      },
      "34": {
        "id": 34,
        build_name: "email_simple",
        build_readable: "Email"
      },
      "35": {
        "id": 35,
        build_name: "email_complex",
        build_readable: "Email"
      },
      "36": {
        "id": 36,
        build_name: "email_half",
        build_readable: "Email"
      },
      "37": {
        "id": 37,
        build_name: "email_half",
        build_readable: "Email"
      }
    },
    last_build_type: '',
    contents_tree: [34, 35, 36, 37, 33]
  },
  computed: {
    buildTypes() {
      const buildTypesMap = {};
      for (id of this.contents_tree) {
        buildTypesMap[id] = this.checkBuildType(id);
      }
      return buildTypesMap
    }
  },
  methods: {
    checkBuildType(id) {
      let check = false;
      if (this.last_build_type !== this.contents[id].build_name) {
        check = true
      }
      this.last_build_type = this.contents[id].build_name;
      return check
    }

  }

})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
  <template v-for="(id, i) in contents_tree">
      <div v-bind:key="i + '_' + id" class="inline">
          <template v-if="buildTypes[id]">
              {{i}} - {{id}} -
              {{contents[id].build_readable}}
              <br>
            
          </template>

</div>
</template>
</div>


contents_tree 确定了顺序。我测试了你写的代码,它检查了内容对象的顺序,但没有检查 contents_tree 数组的顺序。例如,如果你将 contents_tree 更改为 contents_tree=[34, 35, 36, 36],它将无法确定顺序中的最后一项是什么。有什么想法吗? - Jordan
@Jordan,我好像不太明白。只要contents_tree中的id与contents中的id匹配,它就可以工作。计算属性会构建一个类似{34: true, 35: false ...}的映射表。在模板中,它使用方括号来访问对象。所以buildTypes[34] => true。即使有很多重复项,它也应该能正常工作。这个计算属性对顺序没有任何影响。 - AlexMA
contents_tree 的顺序不一定会遵循 contents 对象的顺序。这就是为什么需要 contents_tree 的原因。否则,我将只使用对象的顺序。例如,如果您向 contents 添加一个新的第一个条目:"33": "id": 33, build_name: "email_half", build_readable: "Email",然后让 contents_tree=[34,35,36,33]。在这种情况下,<template v-if 查询应该根据 contents_tree 返回最后一项 33 的 false,但它不会,因为它是 contents 对象中的第一个。 - Jordan
新的计算属性不是一个数组,所以顺序并不重要。只要您的响应性正确连接(在Vue中可能有些棘手-如果您在挂载后添加新项目,请确保使用Vue.set),它将每次重新计算。我理解你的意思,但我认为它并不适用于我的解决方案。如果您仍然相信您的应用程序具有正确的响应性,并且我的答案不正确,请提供可重现的codepen或编辑您的问题,我会修复我的答案。 - AlexMA
这里有一个 CodePen:https://codepen.io/codingcanada/pen/JjdePZj。你可以看到我添加了 33 和 37。37 没有显示出来,这是正确的。但是 33 显示了出来,因为 contents_tree 的顺序没有遵循原始 contents 对象的顺序。 - Jordan
感谢Codepen和良好的沟通。我想我终于明白了 - checkBuildType函数不是幂等的,所以执行顺序很重要,而我执行的顺序是错误的。我相信新的CP可以正确地解决这个问题。 - AlexMA

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接