Vue 生命週期鉤子完整指南

本文翻譯自:
https://learnvue.co/2020/12/how-to-use-lifecycle-hooks-in-vue3/

Vue 2 和 Vue 3 中的生命週期鉤子,其工作方式非常相似。

如果我們在項目中使用 Options API,那就不必更改 Vue 生命週期鉤子的任何代碼,因爲 Vue 3 兼容 Vue 之前的版本。

不過,如果使用的是 Composition API,那麼訪問這些鉤子的方式略有不同。

這篇文章旨在幫助大家瞭解如何在 Options API 和 Composition API 中使用生命週期鉤子,從而寫出更優的代碼。

一起來看看吧!

什麼是 Vue 生命週期鉤子

首先,讓我們來看一下關於 Options API 和 Composition API 中 Vue 3 生命週期鉤子的圖文概述。

從本質上說,每個主要的 Vue 生命週期事件都被分成兩個鉤子,在事件之前和事件之後被調用。你可以在 Vue app 中應用四個主要事件(也就是有 8 個主要鉤子)。

在 Options API 中使用 Vue 生命週期鉤子

使用 Options API 時,生命週期鉤子作爲選項提供給 Vue 實例。我們不需要導入任何東西,只需調用該方法併爲該生命週期鉤子編寫代碼即可。

例如,假設我們要訪問mount()updated()生命週期鉤子。代碼如下:

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

夠簡單了吧?

OK,現在讓我們到 Composition API 中使用 Vue 3 生命週期鉤子。

在 Vue 3 Composition API 中使用 Vue 生命週期鉤子

在 Composition API 中,我們必須先將生命週期鉤子導入到項目中,然後才能使用它們。這是爲了儘可能保持項目的輕量級。

import { onMounted } from 'vue'

除了beforeCreatecreated(它們被setup方法本身所替代),我們可以在setup方法中訪問 9 個 Options API 生命週期鉤子。

當我們導入這些鉤子並在代碼中訪問時,如下所示:

<script>
import { onMounted } from 'vue'

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

更新 Vue 2 代碼爲 Vue 3 生命週期鉤子

這個便捷的 Vue 2 到 Vue 3 生命週期映射就來自於 Vue 3 Composition API 文檔,非常有用。

深入瞭解生命週期鉤子

我們現在知道了兩個重點:

接下來讓我們深入瞭解每個生命週期鉤子,看看是它們如何使用的,我們可以在每個鉤子中編寫什麼樣的代碼,以及它們在 Options API 和 Composition API 中的區別。

組件創建鉤子——VueJS 生命週期的開始

組件創建鉤子是在程序運行要做的第一件事。

beforeCreate()——Options API

由於組件創建鉤子能初始化所有響應性數據和事件,所以beforeCreate不能訪問任何組件的響應性數據和事件。

以下面的代碼塊爲例:

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

val的輸出值是undefined,因爲數據尚未初始化。你也不能在這個方法中調用組件方法。

如果你想看可用內容的完整列表,建議只運行console.log(this)來查看已初始化的內容。當使用 Options API 時,這在所有其他鉤子中也有用。

當你需要某種不需要分配給數據的邏輯 / API 調用時,使用beforeCreate鉤子很有用。因爲如果我們現在給數據分配一些東西,一旦狀態被初始化數據就會丟失。

created()——Options API

我們現在可以訪問組件的數據和事件。因此,修改上面的示例以便使用created代替beforeCreate,並查看輸出如何變化。

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

輸出爲:Value of val is: hello,因爲已經初始化了數據。

在處理讀取 / 寫入響應性數據時,使用created方法很有用。例如,如果你想進行 API 調用,然後存儲該值,就到了created方法大顯身手的時候了。

此處,createdmounted更好,是因爲這是在 Vue 同步初始化過程的早期,並且你可以隨意執行數據讀 / 寫。

至於 Composition API Creation 鉤子怎麼樣?

對於使用 Composition API 的 Vue 3 生命週期鉤子,beforeCreatecreated都被setup()方法替換。這意味着你本應放入這些方法中的任何代碼現在都位於setup方法中。

我們剛剛在創建生命週期鉤子中編寫的代碼得重寫:

import { ref } from 'vue'

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

掛載鉤子——訪問 DOM

這些掛載鉤子處理掛載和渲染組件,是項目和應用程序中最常用的一些鉤子。

beforeMount()onBeforeMount()

在實際渲染和掛載組件 DOM 之前調用。在這一步中,根元素還不存在。在 Options API 中,可以通過this.$el訪問。在 Composition API 中,你必須在根元素上使用ref才能執行此操作。

export default {
   beforeMount() {
     console.log(this.$el)
   }
}

使用ref的 Composition 模板如下所示。

<template>
   <div ref='root'>
     Hello World
   </div>
</template>

然後,對應的腳本嘗試訪問ref

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

mount()onMounted()

在第一次渲染組件後調用。此時元素可用於直接的 DOM 訪問。

在 Options API 中,我們可以使用this.$el來訪問 DOM,而在 Composition API 中,我們需要使用refs來訪問 Vue 生命週期鉤子中的 DOM。

 import { ref, onMounted } from 'vue'
 

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

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

更新鉤子——VueJS 生命週期中的響應性

每當修改響應性數據時都會觸發updated生命週期事件,從而觸發渲染更新。

beforeUpdate()onBeforeUpdate()

在數據更改時,且在重新渲染組件之前運行。這是在發生任何更改之前手動更新 DOM 的好地方。例如,你可以刪除事件偵聽器。

beforeUpdate可用於跟蹤對組件所做的編輯次數,甚至跟蹤創建 undo 功能的操作。

update()onUpdate()

一旦 DOM 更新,就會調用updated方法。下面是一些同時使用beforeUpdateupdated的入門代碼。

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

使用相應的腳本:

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

或者

 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
     }
   }
 }

這些方法很有用,但是我們可能要使用watcher來檢測數據變化以應對很多用例。watcher很不錯,因爲可以給出被更新數據的舊值和新值。

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

銷燬鉤子——清理

組件的銷燬鉤子用於移除所有組件的過程。如果處理不當,刪除事件偵聽器和清理可能導致內存泄漏。

beforeUnmount()onBeforeUnmounted()

這在組件開始銷燬之前調用,此時進行大部分(如果不是全部)清理工作。在這個階段,組件仍然是完全有功效的,也沒有破壞任何東西。

在 Options 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
      }
   }
}

下面是在 Composition 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 () { /* Composition API */

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

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

激活鉤子——管理保持活動的組件

保持活動標籤是動態組件的包裝元素。它存儲對非活動組件的緩存引用,以便 Vue 不必在每次動態組件改變時都要創建一個全新的實例。

對於這個特定的用例,Vue 爲我們提供了兩個生命週期鉤子

activate()onActivated()

每當保持活動的動態組件重新激活時都會調用此方法——這意味着它現在是動態組件的活動視圖。

例如,如果我們使用保持活動的組件來管理不同的選項卡視圖,每次我們在選項卡之間切換時,當前選項卡都會運行這個激活鉤子。

假設我們使用保持活動的包裝器設置了以下動態組件。

<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 () { /* Composition API */
    const tabName = ref('Tab1')

    return {
      tabName
    }
  }
}
</script>

Tab1.vue組件中,我們可以像這樣訪問激活鉤子。

<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()

顧名思義,這在保持活動的組件不再是動態組件的活動視圖時調用。

此鉤子可用於在特定視圖失去焦點保存用戶數據和觸發動畫等用例。

我們可以像這樣捕獲鉤子。

import { onActivated, onDeactivated } from 'vue'

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

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

現在,當我們在選項卡之間切換時——將會緩存和保存每個動態組件的狀態。

Vue 3 調試鉤子

Vue 3 爲我們提供了兩個可用於調試的鉤子,分別是:

這兩個事件都採取了DebuggerEvent,允許我們判斷是什麼導致了 Vue 實例中的重新渲染。

export default {
    onRenderTriggered(e) {
       debugger
       // inspect which dependency is causing the component to re-render
    }
}

總結

無論你決定使用 Options API 還是 Composition API,重要的是不僅要知道要使用什麼生命週期鉤子,還要知道爲什麼要使用它。

生命週期鉤子可以幫助解決很多問題,但關鍵是要選擇最適合當前用例的。

希望這能幫助大家更徹底地瞭解生命週期鉤子以及如何在項目中的實現它。

祝編碼快樂!

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/f3AnidqC5zu4_xrOx2hWJw