本文 AI 產出,尚未審核

Vue3 教學:Lifecycle Hooks(生命週期)— onMountedonUpdatedonUnmounted


簡介

在 Vue 3 中,元件的生命週期是一連串由 Vue 自動觸發的階段,讓開發者可以在適當的時機注入自訂邏輯。掌握 onMountedonUpdatedonUnmounted 三個最常用的 Composition API 生命週期鉤子(hook),不僅能讓程式碼更具可讀性,也能避免因為時機不對而產生的效能或錯誤問題。

本篇文章將以 淺顯易懂 的方式說明這三個 Hook 的運作原理、常見使用情境,以及實務上應該注意的陷阱與最佳實踐,幫助初學者快速上手,同時提供給中階開發者作為日常開發的參考手冊。


核心概念

1. onMounted – 元件掛載完成後執行

onMounted 會在 DOM 元素真正渲染到頁面上 後呼叫,此時可以安全地存取 $el、操作第三方插件、或發送 API 請求取得資料。

import { ref, onMounted } from 'vue'

export default {
  setup() {
    const message = ref('Loading...')

    // 只會在第一次掛載時執行一次
    onMounted(async () => {
      // 假設有一個取得歡迎訊息的 API
      const res = await fetch('/api/welcome')
      const data = await res.json()
      message.value = data.text
    })

    return { message }
  }
}

重點onMounted 只會在首次掛載時觸發,若元件被 v-if 再次顯示,仍會重新呼叫一次。


2. onUpdated – 元件更新(重新渲染)後執行

響應式資料變更,導致模板重新渲染時,onUpdated 會在 DOM 更新完成 後被呼叫。這個 Hook 常用於同步外部 UI(如圖表、動畫)或偵測特定屬性的變化

import { ref, watch, onUpdated } from 'vue'

export default {
  setup() {
    const count = ref(0)

    // 每次 count 改變後,DOM 會重新渲染
    onUpdated(() => {
      console.log('DOM 已更新,最新的 count 為', count.value)
    })

    // 也可以配合 watch 做更細緻的控制
    watch(count, (newVal, oldVal) => {
      console.log(`count 從 ${oldVal} 變成 ${newVal}`)
    })

    const inc = () => count.value++

    return { count, inc }
  }
}

提示onUpdated 會在每一次渲染後執行,若頻繁更新可能會影響效能,請只在需要同步外部資源時使用。


3. onUnmounted – 元件銷毀前執行

當元件從 DOM 中移除(例如 v-iffalse、路由切換等)時,onUnmounted 讓你清理資源:移除事件監聽、關閉 WebSocket、銷毀第三方插件等。

import { ref, onMounted, onUnmounted } from 'vue'

export default {
  setup() {
    const timer = ref(null)

    onMounted(() => {
      // 每秒更新一次時間顯示
      timer.value = setInterval(() => {
        console.log('tick')
      }, 1000)
    })

    onUnmounted(() => {
      // 必須在此清除定時器,避免記憶體洩漏
      clearInterval(timer.value)
      console.log('元件已銷毀,定時器已清除')
    })
  }
}

注意:即使在 v-if 切換 時元件會被銷毀,onUnmounted 仍會正確觸發,確保所有副作用都有機會被釋放。


4. 綜合範例:結合三個 Hook 的完整流程

以下範例示範一個「即時搜尋」元件,使用 onMounted 初始化搜尋 API、onUpdated 監測輸入變化、onUnmounted 清除 debounce 計時器。

import { ref, onMounted, onUpdated, onUnmounted, watch } from 'vue'

export default {
  setup() {
    const query = ref('')
    const results = ref([])
    let debounceTimer = null

    // 初始化時先載入預設資料
    onMounted(async () => {
      const res = await fetch('/api/search?keyword=')
      results.value = await res.json()
    })

    // 當 query 改變時,使用 debounce 減少 API 呼叫次數
    watch(query, (newVal) => {
      clearTimeout(debounceTimer)
      debounceTimer = setTimeout(async () => {
        const res = await fetch(`/api/search?keyword=${encodeURIComponent(newVal)}`)
        results.value = await res.json()
      }, 300) // 300ms 防抖
    })

    // 每次搜尋結果更新後,印出訊息(示範 onUpdated)
    onUpdated(() => {
      console.log('搜尋結果已更新,筆數:', results.value.length)
    })

    // 元件銷毀時清除 debounce 計時器
    onUnmounted(() => {
      clearTimeout(debounceTimer)
    })

    return { query, results }
  }
}

常見陷阱與最佳實踐

陷阱 可能的問題 解決方案 / 實務建議
onMounted 中直接操作 DOM,卻忘記在 SSR(伺服器端渲染)環境下會失效 產生 document is not defined 錯誤 使用 if (import.meta.env.SSR) return 或只在客戶端執行的條件式包住程式碼
onUpdated 內做大量計算,導致渲染卡頓 每次資料變動都觸發,效能下降 盡量把重度運算搬到 watchcomputed,僅在 onUpdatedDOM 同步
忘記在 onUnmounted 清除事件或計時器 記憶體洩漏、意外觸發多次回呼 統一管理:所有 addEventListenersetIntervalWebSocket 都要在 onUnmounted 內對應 removeEventListenerclearIntervalclose
setup 直接使用 this thisundefined(Composition API) 改用 refreactivecomputed,或在 <script setup> 中直接使用變數
watch 裡同時使用 onUpdated,造成重複執行 雙重觸發,難以追蹤 只保留一個機制:若只是監控資料變化,使用 watch;若需要等 DOM 完全更新後再執行,使用 onUpdated

最佳實踐小結

  1. 只在需要時使用 onUpdated:若只是要在資料變化時執行,watch 更合適。
  2. 保持 Hook 的單一職責onMounted 用於初始化、onUpdated 用於同步外部 UI、onUnmounted 用於清理。
  3. 結合 TypeScript:在 setup 中為 refcomputed 加上型別,有助於避免因錯誤的資料型別導致的 runtime 錯誤。
  4. 測試生命週期:使用 Vue Test Utils 的 mountunmount,確保 onMountedonUnmounted 的副作用真的被觸發與清除。

實際應用場景

場景 使用的 Hook 為何選擇
圖表套件(如 Chart.js) onMounted 初始化圖表、onUpdated 更新資料、onUnmounted 銷毀圖表實例 圖表需要 DOM 實體,且資料變動時要重新渲染
WebSocket 連線 onMounted 建立連線、onUnmounted 關閉連線 防止連線遺留在背景,造成資源浪費
自動聚焦表單欄位 onMounted 取得 ref 後呼叫 .focus() 元件渲染完畢才能操作真實的 input 元素
第三方 UI 套件(如 Bootstrap modal) onMounted 初始化 modal、onUpdated 當內容改變時重新調整高度、onUnmounted 銷毀 modal 需要在 DOM 完全就緒後才能正確計算尺寸
SEO / SSR 頁面 onMounted 僅在客戶端執行資料抓取,避免在 SSR 時重複請求 確保伺服器端渲染不會因為 fetch 而卡住

總結

  • onMounted:元件首次掛載完成後執行,適合 初始化DOM 操作API 請求
  • onUpdated:每次資料變動且 DOM 重新渲染後執行,適合 同步外部 UI偵測渲染結果
  • onUnmounted:元件即將銷毀前執行,務必 清理所有副作用(事件、計時器、連線)。

掌握這三個生命週期鉤子,能讓 Vue 3 元件在 效能可維護性資源管理 上都有更佳的表現。未來在實作更複雜的功能時,只要遵循「初始化 → 更新 → 清理」的流程,就能寫出乾淨、可靠的程式碼。祝開發順利,期待你在 Vue 世界裡寫出更多優雅的元件!