Vue 中 強制組件從新渲染的正確方法

做者:Michael Thiessen前端

譯者:前端小智vue

來源:hackernoongit

點贊再看,養成習慣github

本文 GitHub github.com/qq449245884… 上已經收錄,更多往期高贊文章的分類,也整理了不少個人文檔,和教程資料。歡迎Star和完善,你們面試能夠參照考點複習,但願咱們一塊兒有點東西。面試


有時候,依賴 Vue 響應方式來更新數據是不夠的,相反,咱們須要手動從新渲染組件來更新數據。或者,咱們可能只想拋開當前的DOM,從新開始。那麼,如何讓Vue以正確的方式從新呈現組件呢?api

強制 Vue 從新渲染組件的最佳方法是在組件上設置:key。 當咱們須要從新渲染組件時,只需更 key 的值,Vue 就會從新渲染組件。數組

這是一個很是簡單的解決方案。promise

固然,你可能會對其餘方式會更感興趣:工具

  • 簡單粗暴的方式:從新加載整個頁面
  • 不妥的方式:使用 v-if
  • 較好的方法:使用Vue的內置forceUpdate方法
  • 最好的方法:在組件上進行 key 更改

簡單粗暴的方式:從新加載整個頁面

這至關於每次你想關閉應用程序時都要從新啓動你的電腦。學習

這種方式或許有用,但這是一個很是糟糕的解決方案,不要這樣作,咱們來看看更好的方法。

不妥的方式:使用 v-if

v-if指令,該指令僅在組件爲true時才渲染。 若是爲false,則該組件在DOM中不存在。

來看看,v-if 是怎麼工做的,在template中,添加v-if指令:

<template>
  <my-component v-if="renderComponent" />
</template>
複製代碼

script 中,使用nextTick的方法

<script>
  export default {
    data() {
      return {
        renderComponent: true,
      };
    },
    methods: {
      forceRerender() {
        // 從 DOM 中刪除 my-component 組件
        this.renderComponent = false;
        
        this.$nextTick(() => {
          // 在 DOM 中添加 my-component 組件
          this.renderComponent = true;
        });
      }
    }
  };
</script>
複製代碼

上面的過程大體以下:

  1. 剛開始 renderComponent設置爲true,所以渲染 my-component 組件

  2. 當咱們調用forceRerender時,咱們當即將renderComponent設置爲false

  3. 咱們中止渲染my-component,由於v-if指令如今計算結果爲false

  4. nextTick方法中將renderComponent設置回true

  5. v-if指令的計算結果爲true時,再次渲染my-component

在這個過程當中,有兩個部分比較重要

首先,咱們必須等到nextTick,不然咱們不會看到任何變化。

Vue中,一個 tick 是一個DOM更新週期。Vue將收集在同一 tick 中進行的全部更新,在 tick 結束時,它將根據這些更新來渲染 DOM 中的內容。若是咱們不等到next tick,咱們對renderComponent的更新就會自動取消,什麼也不會改變。

其次,當咱們第二次渲染時,Vue將建立一個全新的組件。 Vue 將銷燬第一個,並建立一個新的,這意味着咱們的新my-component將像正常狀況同樣經歷其全部生命週期-createdmounted等。

另外,nextTick 能夠與 promise 一塊兒使用:

forceRerender() {
  // 從 DOM 中刪除 my-component 組件
  this.renderComponent = false;

  this.$nextTick().then(() => {
    this.renderComponent = true;
  });
}
複製代碼

不過,這並非一個很好的解決方案,因此,讓咱們作 Vue 想讓咱們作的

較好的方法:forceUpdate 方法

這是解決這個問題的兩種最佳方法之一,這兩種方法都獲得了Vue的官方支持。

一般狀況下,Vue 會經過更新視圖來響應依賴項中的更改。然而,當咱們調用forceUpdate時,也能夠強制執行更新,即便全部依賴項實際上都沒有改變。

下面是大多數人使用這種方法時所犯的最大錯誤。

若是 Vue 在事情發生變化時自動更新,爲何咱們須要強制更新呢?

緣由是有時候 Vue 的響應系統會讓人感到困惑,咱們認爲Vue會對某個屬性或變量的變化作出響應,但實際上並非這樣。在某些狀況下,Vue的響應系統根本檢測不到任何變化。

因此就像上一個方法,若是你須要這個來從新渲染你的組件,可能有一個更好的方法。

有兩種不一樣的方法能夠在組件實例自己和全局調用forceUpdate

// 全局
import Vue from 'vue';
Vue.forceUpdate();

// 使用組件實例
export default {
  methods: {
    methodThatForcesUpdate() {
      // ...
      this.$forceUpdate();
      // ...
    }
  }
}
複製代碼

重要提示:這不會更新任何計算屬性,調用forceUpdate僅僅強制從新渲染視圖。

最好的方法:在組件上進行 key 更改

在許多狀況下,咱們須要從新渲染組件。

要正確地作到這一點,咱們將提供一個key屬性,以便 Vue 知道特定的組件與特定的數據片斷相關聯。若是key保持不變,則不會更改組件,可是若是key發生更改,Vue 就會知道應該刪除舊組件並建立新組件。

正是咱們須要的!

可是首先,咱們須要繞一小段路來理解爲何在Vue中使用key

爲何咱們須要在 Vue 中使用 key

一旦你理解了這一點,那麼這是瞭解如何以正確方式強制從新渲染的很小的一步。

假設咱們要渲染具備如下一項或多項內容的組件列表:

  • 有本地的狀態

  • 某種初始化過程,一般在createdmounted鉤子中

  • 經過jQuery或普通api進行無響應的DOM操做

若是你對該列表進行排序或以任何其餘方式對其進行更新,則須要從新渲染列表的某些部分。 可是,不會但願從新渲染列表中的全部內容,而只是從新渲染已更改的內容。

爲了幫助 Vue 跟蹤已更改和未更改的內容,咱們提供了一個key屬性。 在這裏使用數組的索引,由於索引沒有綁定到列表中的特定對象。

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,獲得:

Evan - 0
James - 1
複製代碼

James關聯的索引被更改,即便James仍然是JamesJames會被從新渲染,這並非咱們但願的。

因此這裏,咱們可使用惟一的 id 來做爲 key

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刪除了SarahJames的組件,而後爲James建立了一個新組件。如今,Vue知道它能夠爲EvanJames保留這兩個組件,它所要作的就是刪除Sarah的。

若是咱們向列表中添加一個person,Vue 還知道能夠保留全部現有的組件,而且只須要建立一個新組件並將其插入正確的位置。這是很是有用的,當咱們有更復雜的組件,它們有本身的狀態,有初始化邏輯,或者作任何類型的DOM操做時,這對咱們頗有幫助。

因此接下來看看,若是使用最好的方法來從新渲染組件。

更改 key 以強制從新渲染組件

最後,這是強制Vue從新渲染組件的最佳方法(我認爲)。

咱們能夠採用這種將key分配給子組件的策略,可是每次想從新渲染組件時,只需更新該key便可。

這是一個很是基本的方法

<template>
  <component-to-re-render :key="componentKey" />
</template>


export default {
  data() {
    return {
      componentKey: 0,
    };
  },
  methods: {
    forceRerender() {
      this.componentKey += 1;  
    }
  }
}
複製代碼

每次forceRerender被調用時,咱們的componentKey都會改變。當這種狀況發生時,Vue將知道它必須銷燬組件並建立一個新組件。咱們獲得的是一個子組件,它將從新初始化自身並「重置」其狀態。

若是確實須要從新渲染某些內容,請選擇key更改方法而不是其餘方法。


代碼部署後可能存在的BUG無法實時知道,過後爲了解決這些BUG,花了大量的時間進行log 調試,這邊順便給你們推薦一個好用的BUG監控工具 Fundebug

原文:hackernoon.com/the-correct…


交流

乾貨系列文章彙總以下,以爲不錯點個Star,歡迎 加羣 互相學習。

github.com/qq449245884…

我是小智,公衆號「大遷世界」做者,對前端技術保持學習愛好者。我會常常分享本身所學所看的乾貨,在進階的路上,共勉!

關注公衆號,後臺回覆福利,便可看到福利,你懂的。

clipboard.png
相關文章
相關標籤/搜索