Vue之重新渲染組件的正確方式

原文: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知道可以保留EvanJames組件,唯一需要做的就是刪除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;
    }
  }
}
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市景东,隨后出現(xiàn)的幾起案子砂轻,更是在濱河造成了極大的恐慌,老刑警劉巖斤吐,帶你破解...
    沈念sama閱讀 219,270評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件搔涝,死亡現(xiàn)場離奇詭異,居然都是意外死亡曲初,警方通過查閱死者的電腦和手機体谒,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,489評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來臼婆,“玉大人抒痒,你說我怎么就攤上這事“涔樱” “怎么了故响?”我有些...
    開封第一講書人閱讀 165,630評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長颁独。 經(jīng)常有香客問我彩届,道長,這世上最難降的妖魔是什么誓酒? 我笑而不...
    開封第一講書人閱讀 58,906評論 1 295
  • 正文 為了忘掉前任樟蠕,我火速辦了婚禮,結(jié)果婚禮上靠柑,老公的妹妹穿的比我還像新娘寨辩。我一直安慰自己,他們只是感情好歼冰,可當我...
    茶點故事閱讀 67,928評論 6 392
  • 文/花漫 我一把揭開白布靡狞。 她就那樣靜靜地躺著,像睡著了一般隔嫡。 火紅的嫁衣襯著肌膚如雪甸怕。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,718評論 1 305
  • 那天腮恩,我揣著相機與錄音梢杭,去河邊找鬼。 笑死秸滴,一個胖子當著我的面吹牛式曲,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 40,442評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼吝羞,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了内颗?” 一聲冷哼從身側(cè)響起钧排,我...
    開封第一講書人閱讀 39,345評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎均澳,沒想到半個月后恨溜,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,802評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡找前,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,984評論 3 337
  • 正文 我和宋清朗相戀三年糟袁,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片躺盛。...
    茶點故事閱讀 40,117評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡项戴,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出槽惫,到底是詐尸還是另有隱情周叮,我是刑警寧澤,帶...
    沈念sama閱讀 35,810評論 5 346
  • 正文 年R本政府宣布界斜,位于F島的核電站仿耽,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏各薇。R本人自食惡果不足惜项贺,卻給世界環(huán)境...
    茶點故事閱讀 41,462評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望峭判。 院中可真熱鬧开缎,春花似錦、人聲如沸朝抖。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,011評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽治宣。三九已至急侥,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間侮邀,已是汗流浹背坏怪。 一陣腳步聲響...
    開封第一講書人閱讀 33,139評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留绊茧,地道東北人铝宵。 一個月前我還...
    沈念sama閱讀 48,377評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親鹏秋。 傳聞我的和親對象是個殘疾皇子尊蚁,可洞房花燭夜當晚...
    茶點故事閱讀 45,060評論 2 355

推薦閱讀更多精彩內(nèi)容