Watch

Watch 介紹

Watch 是

簡單來說是一種「主動監聽資料變化並執行副作用」的機制

當你使用 watch(source, callback),你就是告訴 Vue:「嘿,如果這個資料(ref、reactive、computed 等)變了,幫我做點事。」這個「做點事」通常是像:呼叫 API、寫入 localStorage、跳出通知、同步外部資料等副作用操作。

和 computed 不同,watch 並不會回傳一個值,而是觸發一段行為。它也不會快取,因為它不是用來算資料的,而是用來回應變化的。

這種「資料變 → 我來做某事」的設計,就是 watch 的本質。

可以把 watch 想像成 Vue 世界裡的「告警系統」,你幫它設定「什麼條件下要叫」,資料一動,它就會「叮~」一聲提醒你,然後你再決定要不要採取行動。

watch()​

  1. 具備「副作用執行」能力的響應式監聽器
  2. 當監聽的資料變動時,立即執行 callback 函式,用來處理非計算邏輯的行為
  3. 實作上會建立一個 effect,並追蹤依賴來源,一旦變化就觸發副作用
  4. 支援多種來源(ref、reactive、getter 函式、陣列組合),也支援選項如 immediate、deep、flush 等以細緻控制執行時機與方式
watch
Preview
<script setup>
import { ref, watch } from "vue";

const count = ref(0);
const message = ref("");

// 監聽 count 變化
watch(
  count,
  (newValue, oldValue) => {
    if (newValue > 10) {
      message.value = "計數超過 10";
    } else {
      message.value = "計數在 10 以下";
    }
  },
  {
    immediate: true, // 初次載入時也執行一次
  }
);
</script>

<template>
  <div>
    <p>當前計數:{{ count }}</p>
    <button class="btn" @click="count++">增加計數</button>
    <button class="btn" @click="count--">減少計數</button>
    <p>{{ message }}</p>
  </div>
</template>

監聽數據源類型

watch() 的第一個參數是「追蹤目標(source)」,可以是:

  • 一個 getter 函式 () => something
  • 一個 ref 物件
  • 一個 reactive 物件(但這樣會監聽整個物件的任意屬性變化)
<script setup>
const x = ref(0)
const y = ref(0)
const obj = reactive({ count: 0 })

// ref
watch(x, (newX) => {
  console.log(`x is ${newX}`)
})

// getter 函式
watch(
  () => x.value + y.value,
  (sum) => {
    console.log(`sum of x + y is: ${sum}`)
  }
)

// 多個來源組成陣列
watch([x, () => y.value], ([newX, newY]) => {
  console.log(`x is ${newX} and y is ${newY}`)
})

// 使用 reactive 若要監聽屬性,必須使用 getter 函式
watch(
  // ❗ 若直接傳入 obj.count,等同於傳入一個 primitive 值(如 number)
  // 這樣 Vue 在初始化 watch 時就會直接取值,無法建立依賴關係
  () => obj.count,
  (count) => {
    console.log(`Count is: ${count}`)
  }
)
</script>

選項

watch 可以加上一些選項來控制監聽的行為,主要有三個常見的選項

immediate
deep
flush

watch 預設是僅當數據源變化時,才會執行回調。通過設定 immediate: true,會在 watch 一被建立就立即執行一次回呼函式。

immediate
<script>
watch(
  source,
    // 立即執行,且當 `source` 改變時再次執行
  (newValue, oldValue) => {...},
  { immediate: true }
)
</script>

watchEffect()

watchEffect 是一種自動收集依賴的副作用函式(reactive effect)。它會「自動偵測你裡面用到的響應式資料」,然後當那些資料變動時,重新執行你寫的程式。

  • 不用明確告訴它要監聽誰
  • 它會看你用到什麼 ref 或 reactive 資料,並幫你追蹤
  • 這讓你可以很快速地「響應某些資料變化並做點事」

與 watch 主要區別是追蹤響應式依賴的方式:

  • watch

    • 只監聽明確定義參數的數據源
    • 不會追蹤任何在回調中的東西
    • 僅在數據源確實改變時才會觸發回調
    • watch 會避免在發生副作用時追蹤依賴,因此,我們能更加精確地控制回調函式的觸發時機
  • watchEffect

    • 會在同步執行過程中,自動追蹤所有能訪問到的響應式屬性
    • 這更方便且程式碼往往更簡潔,但有時其響應性依賴關係會不那麼明確
watch
watchEffect
<script>
const a = ref(1)
const b = ref(2)
const total = ref(0)

// 使用 watch 指定監聽 a 和 b
watch([a, b], ([newA, newB]) => {
  total.value = newA + newB
})

a.value = 3  // 會觸發,計算 total = 5
b.value = 4  // 會觸發,計算 total = 7
</script>

✅ 常見用途

  • 根據資料變化,自動更新畫面邏輯
  • 自動觸發某些副作用(例如打 API、console log、改變其他資料)
  • setup() 裡取代 onMounted + watch 的一些用法
使用場景建議用
監聽一個或多個明確變數(精準控制)watch
根據「使用到的 ref 或 reactive」自動響應watchEffect
初始時跑一次 API 並監聽參數變化時重跑watch + immediate: true
在元件建立時執行 reactive 資料推導或副作用邏輯watchEffect