[Vue warn]: You may have an infinite update loop in a component render function
這個問題很奇怪,之前從來沒有遇到過。如果是我自己主導的項目,倒也好辦,慢慢 debug 就是;偏偏在公司的項目里遇到這個問題,而公司項目的體系結構很復雜,我還沒完全掌握。更惱火的是,因為體系復雜,debug 也非常困難,再加上尚無測試框架,這個難搞啊……
好死不死的,當時是下午3、4點鍾,正好到了肚餓的時刻,結果又落入低血糖狀態,真是屋漏偏逢連陰雨,船小又碰頂頭風,餓得我腦仁生疼……
不過終於還是被我 Google + debug 出來。事實上是這樣的,在 v-for
循環當中,如果用方法或者計算屬性對 vm.$data 的屬性進行操作,理論上,可能因為修改到循環對象,誘發無限循環。此時 Vue 就會發出警告(並不是真的已經無限循環了)。
例如這樣一個組件,它里面是用 :checked + <label>
實現的一組按鈕。它有以下功能:
- 為了能夠分組,需要設置它們的
name
屬性 - 為了能夠用
<label>
控制<input>
,需要給<input>
設置id
- 按鈕可以被刪除
於是我選擇這樣做:
<template>
<div>
<template v-for="(item, index) in items">
<input type="checkbox" :name="'my-component-' + selfIndex" :id="getID">
<label :for="getID(false)">
<button type="button" @click="remove(index)">×</button>
</template>
</div>
</template>
<script>
let count = 0;
export default {
data() {
return {
selfIndex: 0,
itemIndex: 0,
}
},
methods: {
getID(increase = true) { // 注意,問題就出在這里
if (increase) {
this.itemIndex++;
}
return `my-component-${this.selfIndex}-${this.itemIndex}`;
},
},
beforeMount() {
this.selfIndex = count;
count++;
}
}
</script>
這里,為了能生成唯一 ID,我選擇每次循環都對 vm.itemIndex++
,這就會出現前面說的問題,存在隱患。
解決的方案有兩種,一種是把 itemIndex
也放在局部變量里,使它不直接關聯在組件上;另一種則是寫一個全局的唯一 ID 生成函數,然后引用進來。原理都是一樣的。重復的部分就不寫了,修改后大體如下:
方案一
<script>
let count = 0;
let itemCount = 0; // 把元素計數器放在這里
export default {
methods: {
getID(increase = true) {
if (increase) {
itemCount++;
}
return `my-component-${this.selfIndex}-${itemCount}`;
}
}
};
</script>
方案二
// helper.js 生成唯一 id
let count = 0;
export default function uniqueID(increase = true) {
if (increase) {
count++;
}
return `prefix-${count}`;
}
// 原來的組件
import uniqueID from './helper';
export default {
methods: {
getID(increase = true) {
let id = uniqueID(increase);
return `my-component-${this.selfIndex}-${id}`;
}
}
}
【廣告】肉老師的面試題詳解
順便做個廣告,我的新講堂已經上線,將於下周二直播。
這次我決定把自己積累的面試題詳細地介紹給所有來聽課的同學。從設置這道題的目的,考察的方向,希望聽到的答案,答出多少大約是什么評價等等都來個徹底的公開。相信大家聽后,可以更加明確日常學習的方向。
目前還在75折銷售中,歡迎大家,鏈接在此。