最近在写代码的时候遇到一个问题。
场景是父组件引用了子组件,并给子组件传递了一个对象,该对象由父组件中的A方法构造并return。 在父组件的data 中定义了一个变量,在A方法中执行自增。
页面刷新后发现控制台报错:You may have an infinite update loop in a component render function。 代码如下:
父组件:
<template> <div> <h2>杭州西站</h2> <childCpt :params="getObj()"></childCpt> </div></template><script>import childCpt from "@/views/ChildCpt/src/ChildCpt.vue";export default { components: { childCpt }, data() { return { num:0 }; }, methods: { getObj() { //自增 this.num++; let params = {}; params.id = "eeee"; return params; }, }, // 以下为测试内容 // mounted() { // console.log("rerender") // }, // beforeUpdate(){ // console.log("rerender1") // }, // updated(){ // console.log("rerender2") // } };</script>
子组件:
<template> <div> <h2>{{ params.id }}</h2> </div></template><script>export default { props: ["params"], data() { return {}; },};</script>
贴一下测试内容中的打印信息和报错内容
贴不上来图,还是在代码块里展示以上信息....
rerender //打印信息
<101>rerender1 //打印信息
[Vue warn]: You may have an infinite update loop in a component render function.
found in... //报错信息
<102> rerender2 //打印信息
以上,mounted中的打印操作执行了一次,但是beforeUpdate和updated一直不断地在执行,直到报错。
有两个问题:
1. 为什么mounted函数被调用了一次,beforeUpdate和updated却不断被调用?
2. 为什么beforeUpdate和updated会不断被调用,形成无限循环?
问题原因:
num为初始值即0 的时候,进行了一次渲染,完成了节点挂载。
这个过程中,调用了一次mounted,触发了 num的第一次自增,同时data也变化一次。watcher观测到data 的变化,就去调用了beforeUpdate,做虚拟节点更新准备(比如剔除重复的无意义更新)。准备结束后,进入更新阶段 ,源码: vm._update(vm._render(), hydrating)
这个过程中,调用了updated函数,去进行本次页面更新(未真正完成页面本次更新,即真实视图上没有发生变化),在这期间又触发了getObj()的执行,num 再增长一次,data 改变=>beforeUpdate=>updated=>getObj()=>num 增长,闭环,形成无限循环。
ps: 如果页面有自增数字显示之类的需求,可用computed来实现。以下为demo:
<template> <div> <h3>{{numadd}}</h3> </div></template><script>export default { data() { return { num:0 }; }, computed:{ numadd:function(){ setTimeout(()=>{ this.num++ },3000) return this.num } }};</script>