本文 AI 產出,尚未審核

Vue3 生命週期 – onBeforeMount / onBeforeUpdate / onBeforeUnmount


簡介

在 Vue 3 中,生命週期 (Lifecycle) 是每個元件在建立、更新、銷毀過程中會依序觸發的一系列鉤子函式。了解這些鉤子不僅能讓我們在正確的時機插入自訂邏輯,還能避免資源洩漏、效能瓶頸等常見問題。

本單元聚焦於 onBeforeMountonBeforeUpdateonBeforeUnmount 三個「即將」階段的 Hook。它們分別在「掛載前」、「更新前」與「銷毀前」被呼叫,提供我們最後一次機會去準備清理元件。對於需要在畫面渲染前完成資料預處理、在狀態變更前做比對、或在離開頁面前釋放資源的情境,這三個 Hook 是不可或缺的工具。


核心概念

1. onBeforeMount

  • 觸發時機:在 Vue 完成 虛擬 DOM 的建立,但還未把實際 DOM 插入到頁面上時。
  • 典型用途
    • 取得或計算 首次渲染所需的資料,但不想阻塞 setup
    • 設定 第三方 UI 元件(如圖表、地圖)需要的容器尺寸,確保容器已存在於 DOM。
<script setup>
import { ref, onBeforeMount } from 'vue'

const chartData = ref([])

// 假設有一個取得圖表資料的 API
async function fetchChartData() {
  const res = await fetch('/api/chart')
  chartData.value = await res.json()
}

// 在掛載前先取得資料,避免畫面閃爍
onBeforeMount(() => {
  // 這裡可以使用 async/await,但 onBeforeMount 本身不支援返回 Promise
  // 因此直接呼叫非同步函式
  fetchChartData()
})
</script>

<template>
  <div id="chart-container">
    <!-- 這裡的圖表會在資料取得後自動渲染 -->
  </div>
</template>

小技巧:如果需要在 onBeforeMount 中使用 await,可將非同步函式抽離,然後在 Hook 內直接呼叫,Vue 不會等待其完成,渲染會在資料回來後自動更新。


2. onBeforeUpdate

  • 觸發時機:當 響應式狀態 變動,導致元件即將重新渲染 之前
  • 典型用途
    • 比對舊值與新值,決定是否真的需要執行昂貴的計算或 API 請求。
    • 暫存 UI 狀態(如滾動位置、焦點),以便在更新後恢復。
<script setup>
import { ref, onBeforeUpdate, watch } from 'vue'

const searchTerm = ref('')
const results = ref([])

// 每次搜尋前先保存當前的滾動位置
let previousScrollY = 0

onBeforeUpdate(() => {
  // 只在 searchTerm 改變時執行
  if (searchTerm.value !== previousSearch) {
    previousScrollY = window.scrollY   // 保存滾動位置
  }
})

// 監聽 searchTerm 變化,發送搜尋請求
watch(searchTerm, async (newVal, oldVal) => {
  previousSearch = oldVal
  const res = await fetch(`/api/search?q=${newVal}`)
  results.value = await res.json()
})
</script>

<template>
  <input v-model="searchTerm" placeholder="輸入關鍵字搜尋…" />
  <ul>
    <li v-for="item in results" :key="item.id">{{ item.name }}</li>
  </ul>
</template>

注意onBeforeUpdate 只會在 實際的渲染 前被呼叫。如果在同一次更新週期內多次改變同一個響應式屬性,Hook 仍只執行一次。


3. onBeforeUnmount

  • 觸發時機:元件即將從 DOM 中移除,銷毀前
  • 典型用途
    • 清除事件監聽取消訂閱關閉 WebSocket清除計時器
    • 儲存使用者離開前的狀態(如表單草稿),方便下次回來時還原。
<script setup>
import { ref, onBeforeUnmount } from 'vue'

const timerId = ref(null)
const counter = ref(0)

// 每秒遞增計數器
function startTimer() {
  timerId.value = setInterval(() => {
    counter.value++
  }, 1000)
}

// 元件掛載時啟動計時器
startTimer()

// 在元件被銷毀前清除計時器,防止記憶體洩漏
onBeforeUnmount(() => {
  clearInterval(timerId.value)
  console.log('Timer cleared, component is about to be unmounted.')
})
</script>

<template>
  <p>計時器:{{ counter }} 秒</p>
</template>

最佳實踐:所有在 setup 中建立的外部資源(例如 addEventListenersetTimeout、第三方庫的實例)**必須在 onBeforeUnmount 中對應清理,否則即使元件已被移除,仍會持續佔用記憶體或觸發不必要的回呼。


常見陷阱與最佳實踐

陷阱 說明 解決方案
onBeforeMount 使用 await onBeforeMount 不會等待 Promise 完成,導致資料仍在渲染後才回來,出現閃爍或錯誤 UI。 把非同步邏輯抽成獨立函式,或改用 onMounted(會等 DOM 完全掛載)配合 await
onBeforeUpdate 內直接改變響應式資料 會觸發無限更新迴圈,因為每次改變都會再觸發 onBeforeUpdate 僅讀取或使用 nextTick 延遲變更,或在 watch 中處理資料變更。
忘記清理計時器或事件監聽 元件被銷毀後仍持續執行,造成記憶體洩漏或意外行為。 onBeforeUnmount 中統一清除所有外部資源;可將清理函式集中管理(例如返回一個 dispose 函式)。
onBeforeUnmount 中使用已被釋放的變數 若變數在其他地方已被設定為 null,可能拋出錯誤。 確保清理程式碼具備容錯(如 if (timerId) clearInterval(timerId)).
過度依賴 onBeforeUpdate 進行資料請求 每次 UI 更新都發起請求,會造成大量不必要的網路流量。 使用 watchdebounce 來限制請求頻率,僅在關鍵資料變化時才呼叫 API。

最佳實踐小結

  1. 只在必要時使用:若不需要在掛載前就取得資料,直接在 setuponMounted 處理即可。
  2. 保持 Hook 純粹:Hook 應只負責「何時」執行,而非「怎麼」實作。具體邏輯建議抽成可重用的函式。
  3. 統一清理:建立一個 cleanup 陣列,將所有需要在 onBeforeUnmount 執行的函式推入,最後一次迭代執行,提升可維護性。
import { onBeforeUnmount } from 'vue'

const disposers = []

function addDisposer(fn) {
  disposers.push(fn)
}

// 範例:註冊事件
const handler = e => console.log(e)
window.addEventListener('resize', handler)
addDisposer(() => window.removeEventListener('resize', handler))

onBeforeUnmount(() => {
  disposers.forEach(fn => fn())
})

實際應用場景

  1. 圖表套件初始化

    • onBeforeMount 取得容器尺寸,確保圖表在正確寬高下渲染。
    • onBeforeUnmount 釋放圖表實例,避免記憶體佔用。
  2. 表單自動保存草稿

    • 使用 onBeforeUpdate 捕捉使用者輸入變化,將內容暫存到 localStorage
    • onBeforeUnmount 把最後一次草稿寫入持久化儲存,避免遺失。
  3. 單頁應用 (SPA) 中的路由守護

    • 當離開當前頁面前,需要先向後端確認是否有未完成的操作,使用 onBeforeUnmount 發送確認請求。
  4. 即時通訊 (WebSocket) 連線

    • onBeforeMount 建立連線,確保在 UI 出現前已經開始接收資料。
    • onBeforeUnmount 關閉連線,釋放資源。
  5. 動態樣式或動畫

    • onBeforeUpdate 可在狀態改變前暫停動畫,等更新完成後再恢復,避免動畫卡頓。

總結

  • onBeforeMount:元件尚未掛載到真實 DOM 前執行,適合預先取得資料計算容器尺寸初始化第三方套件
  • onBeforeUpdate:在每次渲染前觸發,最適合比對舊新值暫存 UI 狀態限制頻繁的副作用
  • onBeforeUnmount:元件即將被銷毀時呼叫,是清理資源、釋放記憶體的最後防線。

掌握這三個「即將」階段的 Hook,能讓我們在 Vue 3 中寫出更安全、更高效的元件。記得遵守 「只在需要的時機使用」「統一清理」 的原則,讓程式碼保持乾淨、易於維護。祝你在開發 Vue 應用時,玩得開心、寫得順手!