理解 vue3 的 watch 函數

計算屬性允許我們聲明性地計算衍生值。然而在有些情況下,我們需要在狀態變化時執行一些 “副作用”:例如更改 DOM,或是根據異步操作的結果去修改另一處的狀態。

在組合式 API 中,我們可以使用 watch 函數在每次響應式狀態發生變化時觸發回調函數。

偵聽數據源類型

watch 的第一個參數可以是不同形式的 “數據源”:它可以是一個 ref (包括計算屬性)、一個響應式對象、一個 getter 函數、或多個數據源組成的數組:

const x = ref(0)
const y = ref(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}`)
})

注意,你不能直接偵聽響應式對象的屬性值,例如:

const obj = reactive({ count: 0 })
// 錯誤,因爲 watch() 得到的參數是一個 number
watch(obj.count, (count) => {
  console.log(`count is: ${count}`)
})

這裏需要用一個返回該屬性的 getter 函數:

// 提供一個 getter 函數
watch(
  () => obj.count,
  (count) => {
    console.log(`count is: ${count}`)
  }
)

深層偵聽器

直接給 watch() 傳入一個響應式對象,會隱式地創建一個深層偵聽器——該回調函數在所有嵌套的變更時都會被觸發:

const obj = reactive({ count: 0 })
watch(obj, (newValue, oldValue) => {
  // 在嵌套的屬性變更時觸發
  // 注意:`newValue` 此處和 `oldValue` 是相等的
  // 因爲它們是同一個對象!
})
obj.count++

相比之下,一個返回響應式對象的 getter 函數,只有在返回不同的對象時,纔會觸發回調:

watch(
  () => state.someObject,
  () => {
    // 僅當 state.someObject 被替換時觸發
  }
)

你也可以給上面這個例子顯式地加上 deep 選項,強制轉成深層偵聽器:

watch(
  () => state.someObject,
  (newValue, oldValue) => {
    // 注意:`newValue` 此處和 `oldValue` 是相等的
    // *除非* state.someObject 被整個替換了
  },
  { deep: true }
)

謹慎使用

深度偵聽需要遍歷被偵聽對象中的所有嵌套的屬性,當用於大型數據結構時,開銷很大。因此請只在必要時才使用它,並且要留意性能。

總結

watch() 默認是懶偵聽的,即僅在偵聽源發生變化時才執行回調函數。

第一個參數是偵聽器的源。這個來源可以是以下幾種:

  1. 一個函數,返回一個值 2. 一個 ref3. 一個響應式對象 4.... 或是由以上類型的值組成的數組

第二個參數是在發生變化時要調用的回調函數。

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