Vue 3 生命週期完整指南

2021-03-31 09:01:02
作者:Michael Thiessen
譯者:前端小智
來源:news
點贊再看,微信搜尋大遷世界,B站關注前端小智這個沒有大廠背景,但有著一股向上積極心態人。本文 GitHub https://github.com/qq44924588... 上已經收錄,文章的已分類,也整理了很多我的檔案,和教學資料。

最近開源了一個 Vue 元件,還不夠完善,歡迎大家來一起完善它,也希望大家能給個 star 支援一下,謝謝各位了。

github 地址:https://github.com/qq44924588...

image.png

Vue2 和 Vue3 中的生命週期勾點的工作方式非常相似,我們仍然可以存取相同的勾點,也希望將它們能用於相同的場景。

如果專案使用 選項 API,就不必更改任何程式碼了,因為 Vue3 相容以前的版本。

當然,我們用 Vue3 就是要用它的 組合 API組合 API中存取這些勾點的方式略有不同,組合API在較大的Vue專案中特別有用。

本文主要內容:

  1. Vue生命週期勾點有哪些
  2. 選項API中使用 Vue 生命週期勾點
  3. 組合API中使用Vue 3生命週期勾點
  4. 將 Vue2 的生命週期勾點程式碼更新到 Vue3
  5. 看看Vue 2和Vue 3中的每個生命週期勾點

    1. 建立
    2. 掛載
    3. 更新
    4. 解除安裝
    5. 啟用
  6. Vue 3中的新偵錯勾點

Vue生命週期勾點有哪些

首先,來看一下 選項API 和 組合 API中 Vue 3生命週期勾點的圖表。在深入細節之前,這能加深我們的理解。

image.png

本質上,每個主要Vue生命週期事件被分成兩個勾點,分別在事件之前和之後呼叫。Vue應用程式中有4個主要事件(8個主要勾點)。

  • 建立 — 在元件建立時執行
  • 掛載 — DOM 被掛載時執行
  • 更新 — 當響應資料被修改時執行
  • 銷燬 — 在元素被銷燬之前立即執行

選項API中使用 Vue 生命週期勾點

使用 選項API,生命週期勾點是被暴露 Vue範例上的選項。我們不需要匯入任何東西,只需要呼叫這個方法併為這個生命週期勾點編寫程式碼。

例如,假設我們想存取mounted()updated()生命週期勾點,可以這麼寫:

// 選項 API
<script>     
   export default {         
      mounted() {             
         console.log('mounted!')         
      },         
      updated() {             
         console.log('updated!')         
      }     
   }
</script> 

組合API中使用Vue 3生命週期勾點

在組合API中,我們需要將生命週期勾點匯入到專案中,才能使用,這有助於保持專案的輕量性。

// 組合 API
import { onMounted } from 'vue'

除了beforecatecreated(它們被setup方法本身所取代),我們可以在setup方法中存取的API生命週期勾點有9個選項:

  • onBeforeMount – 在掛載開始之前被呼叫:相關的 render 函數首次被呼叫。
  • onMounted – 元件掛載時呼叫
  • onBeforeUpdate – 資料更新時呼叫,發生在虛擬 DOM 打修補程式之前。這裡適合在更新之前存取現有的 DOM,比如手動移除已新增的事件監聽器。
  • onUpdated – 由於資料更改導致的虛擬 DOM 重新渲染和打修補程式,在這之後會呼叫該勾點。
  • onBeforeUnmount – 在解除安裝元件範例之前呼叫。在這個階段,範例仍然是完全正常的。
  • onUnmounted – 解除安裝元件範例後呼叫。呼叫此勾點時,元件範例的所有指令都被解除繫結,所有事件偵聽器都被移除,所有子元件範例被解除安裝。
  • onActivated – 被 keep-alive 快取的元件啟用時呼叫。
  • onDeactivated – 被 keep-alive 快取的元件停用時呼叫。
  • onErrorCaptured – 當捕獲一個來自子孫元件的錯誤時被呼叫。此勾點會收到三個引數:錯誤物件、發生錯誤的元件範例以及一個包含錯誤來源資訊的字串。此勾點可以返回 false 以阻止該錯誤繼續向上傳播。

使用事例:

// 組合 API
<script>
import { onMounted } from 'vue'

export default {
   setup () {
     onMounted(() => {
       console.log('mounted in the composition api!')
     })
   }
}
</script>

將 Vue2 的生命週期勾點程式碼更新到 Vue3

這個從Vue2 到Vue3的生命週期對映是直接從Vue 3 Composition API檔案中獲得的:

  • beforeCreate -> 使用 setup()
  • created -> 使用 setup()
  • beforeMount -> onBeforeMount
  • mounted -> onMounted
  • beforeUpdate -> onBeforeUpdate
  • updated -> onUpdated
  • beforeDestroy -> onBeforeUnmount
  • destroyed -> onUnmounted
  • errorCaptured -> onErrorCaptured

深入瞭解每個生命週期勾點

我們現在瞭解了兩件重要的事情:

  • 我們可以使用的不同的生命週期勾點
  • 如何在選項API和組合API中使用它們

我們深入一下每個生命週期勾點,看看它們是如何被使用的,我們可以在每個勾點中編寫特定程式碼,來測試在Options API和Composition API中的各自的區別。

beforeCreate() – 選項 API

由於建立的掛鉤是用於初始化所有響應資料和事件的事物,因此beforeCreate無法存取元件的任何響應資料和事件。

以下面的程式碼塊為例:

// 選項 API
export default {
   data() { 
     return { 
       val: 'hello'    
     }
   },
   beforeCreate() {     
     console.log('Value of val is: ' + this.val)   
   }
}

val的輸出值是 undefined,因為尚未初始化資料,我們也不能在這呼叫元件方法。

如果你想檢視可用內容的完整列表,建議只執行console.log(this)來檢視已初始化的內容。當使用選項API時,這做法在其他勾點中也很有用。

created() – 選項 API

如果我們要在元件建立時存取元件的資料和事件,可以把上面的 beforeCreatecreated代替。

// 選項API
export default {
   data() { 
     return { 
       val: 'hello'    
     }
   },
   created() {     
     console.log('Value of val is: ' + this.val)   
   }
}

其輸出為Value of val is: hello,因為我們已經初始化了資料。

在處理讀/寫反應資料時,使用created 的方法很有用。 例如,要進行API呼叫然後儲存該值,則可以在此處進行此操作。

最好在這裡執行此操作,而不是在mounted 中執行此操作,因為它發生在Vue的同步初始化過程中,並且我們需要執行所有資料讀取/寫入操作。

那麼組合API的建立勾點呢?

對於使用 組合API 的 Vue3 生命週期勾點,使用setup()方法替換beforecatecreated。這意味著,在這些方法中放入的任何程式碼現在都只在setup方法中。

// 組合AP
import { ref } from 'vue'

export default {
   setup() {    
     const val = ref('hello') 
     console.log('Value of val is: ' + val.value)       
     return {         
       val
     }
   }
}

beforeMount() and onBeforeMount()

在元件DOM實際渲染安裝之前呼叫。在這一步中,根元素還不存在。在選項API中,可以使用this.$els來存取。在組合API中,為了做到這一點,必須在根元素上使用ref

// 選項 API
export default {
   beforeMount() {
     console.log(this.$el)
   }
 }

組合API中使用 ref:

// 組合 API
<template>
   <div ref='root'>
     Hello World
   </div>
</template> 

import { ref, onBeforeMount } from 'vue'

export default {
   setup() {
      const root = ref(null) 
      onBeforeMount(() => {   
         console.log(root.value) 
      }) 
      return { 
         root
      }
    },
    beforeMount() {
      console.log(this.$el)
    }
 }

因為app.$el還沒有建立,所以輸出將是undefined

mounted() and onMounted()

在元件的第一次渲染後呼叫,該元素現在可用,允許直接DOM存取

同樣,在 選項API中,我們可以使用this.$el來存取我們的DOM,在組合API中,我們需要使用refs來存取Vue生命週期勾點中的DOM。

import { ref, onMounted } from 'vue'
 

 export default {
   setup() {    /* 組合 API */
 
     const root = ref(null)
 
     onMounted(() => {
       console.log(root.value)
     })
 

     return {
       root
     }
   },
   mounted() { /* 選項 API */
     console.log(this.$el)
   }
 } 

beforeUpdate() and onBeforeUpdate()

資料更新時呼叫,發生在虛擬 DOM 打修補程式之前。這裡適合在更新之前存取現有的 DOM,比如手動移除已新增的事件監聽器。

beforeUpdate對於跟蹤對元件的編輯次數,甚至跟蹤建立「撤消」功能的操作很有用。

updated() and onUpdated()

DOM更新後,updated的方法即會呼叫。

<template>
    <div>
      <p>{{val}} | edited {{ count }} times</p>
      <button @click='val = Math.random(0, 100)'>Click to Change</button>
    </div>
 </template> 

選項 API 方式:

 export default {
   data() {
      return {
        val: 0
      }
   },
   beforeUpdate() {
      console.log("beforeUpdate() val: " + this.val)
   },
   updated() {
      console.log("updated() val: " + this.val
   }
 } 

組合API的方式:

import { ref, onBeforeUpdate, onUpdated } from 'vue'
 
 export default {
   setup () {
     const count = ref(0)
     const val = ref(0)
 
     onBeforeUpdate(() => {
       count.value++;
       console.log("beforeUpdate");
     })
 
     onUpdated(() => {
       console.log("updated() val: " + val.value)
     })
 
     return {
       count, val
     }
   }
 }

這些方法很有用,但是對於更多場景,我們需要使用的watch方法檢測這些資料更改。 watch 之所以好用,是因為它給出了更改後的資料的舊值和新值。

另一種選擇是使用計算屬性來基於元素更改狀態。

beforeUnmount() 和 onBeforeUnmounted()

在解除安裝元件範例之前呼叫。在這個階段,範例仍然是完全正常的。

在 選項 API中,刪除事件偵聽器的範例如下所示。

// 選項 API
export default {
   mounted() {
     console.log('mount')
     window.addEventListener('resize', this.someMethod);
   },
   beforeUnmount() {
     console.log('unmount')
     window.removeEventListener('resize', this.someMethod);
   },
   methods: {
      someMethod() {
         // do smth
      }
   }
} 
// 組合API
import { onMounted, onBeforeUnmount } from 'vue' 

 export default {
   setup () {
 
     const someMethod = () => {
       // do smth
     }
 
     onMounted(() => {
       console.log('mount')
       window.addEventListener('resize', someMethod);
     })
 
     onBeforeUnmount(() => {
       console.log('unmount')
       window.removeEventListener('resize', someMethod);
     })
 
   }
 }

實際操作的一種方法是在Vite,vue-cli或任何支援熱過載的開發環境中,更新程式碼時,某些元件將自行解除安裝並安裝。

unmounted() 和 onUnmounted()

解除安裝元件範例後呼叫。呼叫此勾點時,元件範例的所有指令都被解除繫結,所有事件偵聽器都被移除,所有子元件範例被解除安裝。

import { onUnmounted } from 'vue'

export default {
  setup () { /* 組合 API */

    onUnmounted(() => {
      console.log('unmounted')
    })

  },
  unmounted() { /* 選項 API */
    console.log('unmounted')
  }
}

activated() and onActivated()

keep-alive 快取的元件啟用時呼叫。

例如,如果我們使用keep-alive元件來管理不同的索引標籤檢視,每次在索引標籤之間切換時,當前索引標籤將執行這個 activated 勾點。

假設我們使用keep-alive包裝器進行以下動態元件。

<template>
   <div>
     <span @click='tabName = "Tab1"'>Tab 1 </span>
     <span @click='tabName = "Tab2"'>Tab 2</span>
     <keep-alive>
       <component :is='tabName' class='tab-area'/>
     </keep-alive>
   </div>
</template>

<script>
import Tab1 from './Tab1.vue'
import Tab2 from './Tab2.vue'

import { ref } from 'vue'

export default {
  components: {
    Tab1,
    Tab2
  },
  setup () { /* 組合 API */
    const tabName = ref('Tab1')

    return {
      tabName
    }
  }
}
</script>

Tab1.vue元件內部,我們可以像這樣存取activated勾點。

<template>
 <div>
 <h2>Tab 1</h2>
 <input type='text' placeholder='this content will persist!'/>
 </div>
</template>

<script>
import { onActivated } from 'vue'

export default {
 setup() {
    onActivated(() => {
       console.log('Tab 1 Activated')
    })
 }
} 
</script>

deactivated() 和 onDeactivated()

keep-alive 快取的元件停用時呼叫。

這個勾點在一些用例中很有用,比如當一個特定檢視失去焦點時儲存使用者資料和觸發動畫。

import { onActivated, onDeactivated } from 'vue'

export default {
  setup() {
    onActivated(() => {
       console.log('Tab 1 Activated')
    })

    onDeactivated(() => {
       console.log('Tab 1 Deactivated')
    })
  }
}

現在,當我們在索引標籤之間切換時,每個動態元件的狀態都將被快取和儲存。

image

Vue3 偵錯勾點

Vue3 為我們提供了兩個可用於偵錯目的的勾點。

  1. onRenderTracked
  2. onRenderTriggered

這兩個事件都帶有一個debugger event,此事件告訴你哪個操作跟蹤了元件以及該操作的目標物件和鍵。

onRenderTracked

跟蹤虛擬 DOM 重新渲染時呼叫。勾點接收 debugger event 作為引數。此事件告訴你哪個操作跟蹤了元件以及該操作的目標物件和鍵。

<div id="app">
  <button v-on:click="addToCart">Add to cart</button>
  <p>Cart({{ cart }})</p>
</div>
const app = Vue.createApp({
  data() {
    return {
      cart: 0
    }
  },
  renderTracked({ key, target, type }) {
    console.log({ key, target, type })
    /* 當元件第一次渲染時,這將被記錄下來:
    {
      key: "cart",
      target: {
        cart: 0
      },
      type: "get"
    }
    */
  },
  methods: {
    addToCart() {
      this.cart += 1
    }
  }
})

app.mount('#app')

renderTracked

當虛擬 DOM 重新渲染為 triggered.Similarly 為renderTracked,接收 debugger event 作為引數。此事件告訴你是什麼操作觸發了重新渲染,以及該操作的目標物件和鍵。

用法:

<div id="app">
  <button v-on:click="addToCart">Add to cart</button>
  <p>Cart({{ cart }})</p>
</div>
const app = Vue.createApp({
  data() {
    return {
      cart: 0
    }
  },
  renderTriggered({ key, target, type }) {
    console.log({ key, target, type })
  },
  methods: {
    addToCart() {
      this.cart += 1
      /* 這將導致renderTriggered呼叫
        {
          key: "cart",
          target: {
            cart: 1
          },
          type: "set"
        }
      */
    }
  }
})

app.mount('#app')

總結

無論你選擇使用選項API還是 組合API,不僅要知道要使用哪個生命週期掛鉤,而且要知道為什麼要使用它,這一點很重要。

對於許多問題,可以使用多個生命週期勾點。但是最好知道哪個是最適合你用例的。無論如何,你都應該好好考慮一下,並有充分的理由去選擇一個特定的生命週期勾點。

我希望這能幫助大家更多地理解生命週期勾點以及如何在大家的專案中實現它們。

~完,我是刷碗智,我要去刷碗了,骨的白。


程式碼部署後可能存在的BUG沒法實時知道,事後為了解決這些BUG,花了大量的時間進行log 偵錯,這邊順便給大家推薦一個好用的BUG監控工具 Fundebug

原文:https://learnvue.co/2020/12/h...

交流

文章每週持續更新,可以微信搜尋「 大遷世界 」第一時間閱讀和催更(比部落格早一到兩篇喲),本文 GitHub https://github.com/qq449245884/xiaozhi 已經收錄,整理了很多我的檔案,歡迎Star和完善,大家面試可以參照考點複習,另外關注公眾號,後臺回覆福利,即可看到福利,你懂的。