iT邦幫忙

2025 iThome 鐵人賽

DAY 12
0
Vue.js

新手學習Vue.js與實作之旅系列 第 12

Day 12 Vue 監聽器

  • 分享至 

  • xImage
  •  

昨天提到計算屬性 Computed 是根據相依的資料發生改變,才會重新執行運算,否則就會直接返回暫存的結果,而今天要介紹的監聽器 watch 是根據響應式資料發生改變,而做出一些延伸的應用。

監聽器 Watchers 是什麼 ?

當監聽到資料發生改變時,可以做出其他延伸的應用 (稱作 side effect),例如:修改資料、發送 API 請求資料或觸發 function 執行等。

基本語法

watch 函數中總共有以下三個參數:

  • source
    寫入監聽對象,例如:ref、reactive、getter、陣列等。
  • callback
    可以在箭頭函式加上 (newValue, oldValue) 接收參數,並且在{ }內寫入side effect。
  • options
    可以選擇性使用來增強功用,例如:deep、immediate、once、flush 等屬性。
watch(
  source,
  callback, 
  {options} 
)

以下是官方文件的範例 (Composition API)

當監聽到 question 內容改變時,原本畫面中的 answer 是空值,直到拿到新的值,畫面就會產生變化,也就是說 watch 在資料變化時觸發 side effect,進而修改狀態或取得新的資料,並即時呈現在畫面上。

<script setup>
import { ref, watch } from 'vue'

const question = ref('')
const answer = ref('Questions usually contain a question mark. ;-)')
const loading = ref(false)

// 可以直接偵聽一個 ref
watch(question, async (newQuestion, oldQuestion) => {
  if (newQuestion.includes('?')) {
    loading.value = true
    answer.value = 'Thinking...'
    try {
      const res = await fetch('https://yesno.wtf/api')
      answer.value = (await res.json()).answer
    } catch (error) {
      answer.value = 'Error! Could not reach the API. ' + error
    } finally {
      loading.value = false
    }
  }
})
</script>

<template>
  <p>
    Ask a yes/no question:
    <input v-model="question" :disabled="loading" />
  </p>
  <p>{{ answer }}</p>
</template>

https://ithelp.ithome.com.tw/upload/images/20250915/20169120iibFEczHFu.png

接下來要更深入探討 watch 函數中第三個參數可以寫入的屬性

  • deep
    透過將 watch 的第三個參數寫入 {deep: true},就可以監聽內部深層資料的改變,但深層監聽(Deep Watchers)會遍歷物件所有屬性,因此在資料龐大的狀況下會非常耗能。

  • immediate
    預設是直到監聽對象改變時才會觸發執行函式,透過將 watch 的第三個參數寫入 { immediate: true } 就可以馬上執行。

  • once
    當想要 watch 只執行一次時,可以在 watch 的第三個參數寫入 { once: true } 。

最後要介紹 watchEffect

提供更簡潔的監聽方式,無需指定監聽對象,callBack 沒有放參數也可以使用,而且不需要特別加入 immediate 屬性,就會自動追蹤 callBack 函數中使用到的所有響應式資料。

基本語法

watchEffect(() => {  }) // 在大括號內寫入 side effect

以下是官方文件的範例 (Composition API)

使用 watch函數

const todoId = ref(1)
const data = ref(null)

watch(
  todoId,
  async () => {
    const response = await fetch(
      `https://jsonplaceholder.typicode.com/todos/${todoId.value}`
    )
    data.value = await response.json()
  },
  { immediate: true }
)

使用 watchEffect 函數

watchEffect(async () => {
  const response = await fetch(
    `https://jsonplaceholder.typicode.com/todos/${todoId.value}`
  )
  data.value = await response.json()
})

總結: watch vs. watchEffect

  • watch

    • 只追蹤明確指定的監聽對象,不會自動追蹤 callBack 函數中的其他響應式資料
    • 僅在指定對象改變時觸發
    • 預設不會在初始化時執行(需要使用 immediate: true
    • 提供 newValueoldValue 參數
  • watchEffect

    • 自動追蹤 callBack 函數中訪問到的所有響應式資料
    • 任何被追蹤的資料改變都會觸發重新執行
    • 初始化時會立即執行一次
    • callBack 函數沒有參數
    • 寫法更簡潔,適合監聽多個資料源

參考資源

https://zh-hk.vuejs.org/guide/essentials/watchers.html
https://medium.com/@marsuo52_70945/vue3-watch-watcheffect%E6%80%8E%E9%BA%BC%E7%94%A8-208b2ab2ea0c
https://ithelp.ithome.com.tw/m/articles/10325354
https://ithelp.ithome.com.tw/articles/10308600


上一篇
Day11 Vue 計算屬性
下一篇
Day13 Vue 元件的生命週期
系列文
新手學習Vue.js與實作之旅14
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言