原文:https://michaelnthiessen.com/force-re-render/
以下為翻譯篇卖怜,如有不正確之處還望留言指正垃环。
當你只想重新渲染某個組件蝗碎,或者銷毀當前DOM并重新開始氮双, 這個時候Vue的響應系統(tǒng)就差點兒意思。那如果是你遇到類似情況的話董瞻,會怎么辦呢?
最行之有效的辦法就是給component設置一個:key,當你需要重新渲染這個組件的時候只需要修改key的值即可浩嫌。
這難道不是一個相當簡單的解決辦法嗎?
還有一些其他的方法可以實現(xiàn)相同的效果:
- reloading整個頁面 【最差的一種方式】
- 使用v-if【一般的方式】
- forceUpdate【比較好的方式】
- key-changing 【最好的方式】
如果你想強制重新加載或者強制更新补胚,下面會可能是比較好的方式码耐。
很有可能你對相面的幾件事情比較迷惑:
1、Vue的響應式
2溶其、計算屬性
3骚腥、監(jiān)聽器
4、v-for未使用:key
這里有幾個強制刷新的可用Demo瓶逃,大部分都可以通過key-changing方式解決束铭,關于技術的原理在文章的末尾。
reloading整個頁面
這是一種類似于“你每次想退出app時都要通過重啟電腦”的方式厢绝。
我猜想這種方式有時也會很有效契沫,但是確實是個比較糟糕的方式,這里就不必多言昔汉,不要這么干了懈万,可以看看其他比較好的方式。
v-if
Vue的v-if指令只有當true時才會顯示靶病,false則會將其從DOM中剔除会通,接下來我們來看看怎么做的。
<template>
<my-component v-if="renderComponent"/>
</template>
<script>
export default {
data() {
return {
renderComponent: true,
};
},
methods: {
forceRerender() {
// Remove my-component from the DOM
this.renderComponent = false;
this.$nextTick(() => {
// Add the component back in
this.renderComponent = true;
});
}
}
};
</script>
流程分析:
1娄周、初始化的時候renderComponent值為true涕侈,組件渲染
2、當我們調(diào)用forceRerender時煤辨,renderComponent會立刻變?yōu)閒alse裳涛,
3木张、這個時候因為值為false組件就會停止渲染,
4调违、然后在next tick里面將renderComponent的值重新設置回去窟哺,
5、現(xiàn)在組件就會開始重新渲染
上面的流程主要有兩個重要的點需要理解:
1技肩、必須要在nextTick以后才能更改且轨,否則會看不到效果
在Vue中,DOM的更新周期即為一個tick虚婿,在同一個tick內(nèi)Vue會搜集變化旋奢,然后在tick的最后會根據(jù)變化的值去更新節(jié)點,如果我們不等到next tick然痊,直接更新變量的值至朗,不會觸發(fā)節(jié)點的更新。
2剧浸、當我們重新渲染的時候锹引,Vue將會創(chuàng)建一個新的組件。Vue銷毀之前的重新創(chuàng)建新的意味著新的組件會重新走一遍生命周期唆香。
forceUpdate
和前面的方式對比嫌变,這種也是官方支持的、比較好的方式躬它。
正常來講腾啥,Vue會根據(jù)依賴的值變化去更新界面,當然冯吓,如果你調(diào)用forceUpdate
倘待,就算依賴的值未變化也會強制更新。
這里有個問題:Vue既然能根據(jù)值的變化去自動更新组贺,那為啥我們還需要強制更新呢凸舵?
這個是因為有的時候Vue的響應系統(tǒng)會有困惑,我們認為Vue會根據(jù)某些屬性或變量的值變化去更新失尖,結(jié)果并沒有贞间,而且還有一些其他的情況是響應系統(tǒng)檢測不到的。所以如果你有重新渲染組件的需要時這種方式比較好雹仿。
需要注意的是:forceUpdate
只會強制更新頁面,不會更新現(xiàn)有的計算屬性整以。
key-changing
在很多種情況下你可能都會有重新渲染組件的需求胧辽,為了比較好的解決這種問題,我們將使用key
屬性以便Vue能夠?qū)?shù)據(jù)和組件建立起關系公黑。如果key不變邑商,就不更新摄咆。一旦key發(fā)生變化,Vue就會剔除舊的創(chuàng)建新的組件人断。
使用之前我們先看一下為什么要使用key
!
當你明白了這個問題以后你對如果正確的重新渲染組件會有不小的進步吭从。
假設您要呈現(xiàn)的組件列表具有以下一個或多個特點:
- 自有屬性
- 初始化處理,比如在
created
或者mounted
鉤子函數(shù)中 - 通過jQuery或者APIs的非響應式DOM操作
如果你對這個列表進行排序或者更新恶迈,你都需要重新渲染列表的部分界面涩金,但是你不想將整個列表重新渲染,而僅僅是將修改的過的進行更新暇仲。
為了幫助Vue框架能夠監(jiān)測哪些值發(fā)生改變步做,哪些值未變,我們提供了key
屬性奈附,因為在列表的特殊對象和其索引index
沒有進行綁定全度,
這兒有個例子:
const people = [
{ name: 'Evan', age: 34 },
{ name: 'Sarah', age: 98 },
{ name: 'James', age: 45 },
];
如果你想通過索引渲染,可能會這么寫:
<ul>
<li v-for="(person, index) in people" :key="index">
{{ person.name }} - {{ index }}
</li>
</ul>
// Outputs
Evan - 0
Sarah - 1
James - 2
如果我們刪除Sarah
斥滤,會得到如下結(jié)果:
Evan - 0
James - 1
雖然James
仍然是James
将鸵,但是和其關聯(lián)的索引已經(jīng)改變。James
會被重新渲染佑颇,雖然我們不想那樣顶掉。
所以在這里,我們想用某種獨特的ID漩符,但是我們最終生成它一喘。
const people = [
{ id: 'this-is-an-id', name: 'Evan', age: 34 },
{ id: 'unique-id', name: 'Sarah', age: 98 },
{ id: 'another-unique-id', name: 'James', age: 45 },
];
<ul>
<li v-for="person in people" :key="person.id">
{{ person.name }} - {{ person.id }}
</li>
</ul>
在我們將 Sarah
從列表中移除前,Vue為了另外兩個先刪除組件嗜暴,然后再給James
創(chuàng)建一個組件凸克,現(xiàn)在Vue知道可以保留Evan
和James
組件,唯一需要做的就是刪除Sarah
的組件.
如果再加上一個人到列表中闷沥,它也知道它可以保持現(xiàn)有的所有組件萎战,并且它只能建立一個新的組件,并將其插入正確的位置舆逃。這是非常有用的蚂维,并幫助了我們很多的時候,我們有更復雜的組件都有自己的狀態(tài)路狮,必須初始化邏輯虫啥,或做任何類型的DOM操作。
也許這彎路也沒那么短奄妨。但是涂籽,有必要解釋Vue是如何工作的很關鍵。
不管怎么說砸抛,讓我們與強迫重新渲染的最佳方法评雌!
Key-changing to force re-renders of a component
這里是做的一個非呈鞣悖基本的方法:
<template>
<component-to-re-render :key="componentKey" />
</template>
export default {
data() {
return {
componentKey: 0,
};
},
methods: {
forceRerender() {
this.componentKey += 1;
}
}
}