欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

VUE3數(shù)據(jù)的偵聽超詳細講解

 更新時間:2023年12月28日 09:51:41   作者:前端不加班  
在Vue3中watch特性進行了一些改變和優(yōu)化,與computed不同,watch通常用于監(jiān)聽數(shù)據(jù)的變化,并執(zhí)行一些副作用,這篇文章主要給大家介紹了關于VUE3數(shù)據(jù)偵聽的相關資料,需要的朋友可以參考下

前言

偵聽數(shù)據(jù)變化也是組件里的一項重要工作,比如偵聽路由變化、偵聽參數(shù)變化等等。

Vue 3 在保留原來的 watch 功能之外,還新增了一個 watchEffect 幫助更簡單的進行偵聽。

watch

在 Vue 3 ,新版的 watch 和 Vue 2 的舊版寫法對比,在使用方式上變化非常大!

回顧 Vue 2

在 Vue 2 是這樣用的,和 data 、 methods 都在同級配置:

export default {
  data() {
    return {
      // ...
    }
  },
  // 注意這里,放在 `data` 、 `methods` 同個級別
  watch: {
    // ...
  },
  methods: {
    // ...
  },
}

并且類型繁多,選項式 API 的類型如下:

watch: { [key: string]: string | Function | Object | Array}

聯(lián)合類型過多,意味著用法復雜,下面是個很好的例子,雖然出自 官網(wǎng) 的用法介紹,但過于繁多的用法也反映出來對初學者不太友好,初次接觸可能會覺得一頭霧水:

export default {
  data() {
    return {
      a: 1,
      b: 2,
      c: {
        d: 4,
      },
      e: 5,
      f: 6,
    }
  },
  watch: {
    // 偵聽頂級 Property
    a(val, oldVal) {
      console.log(`new: ${val}, old: ${oldVal}`)
    },
    // 字符串方法名
    b: 'someMethod',
    // 該回調(diào)會在任何被偵聽的對象的 Property 改變時被調(diào)用,不論其被嵌套多深
    c: {
      handler(val, oldVal) {
        console.log('c changed')
      },
      deep: true,
    },
    // 偵聽單個嵌套 Property
    'c.d': function (val, oldVal) {
      // do something
    },
    // 該回調(diào)將會在偵聽開始之后被立即調(diào)用
    e: {
      handler(val, oldVal) {
        console.log('e changed')
      },
      immediate: true,
    },
    // 可以傳入回調(diào)數(shù)組,它們會被逐一調(diào)用
    f: [
      'handle1',
      function handle2(val, oldVal) {
        console.log('handle2 triggered')
      },
      {
        handler: function handle3(val, oldVal) {
          console.log('handle3 triggered')
        },
        /* ... */
      },
    ],
  },
  methods: {
    someMethod() {
      console.log('b changed')
    },
    handle1() {
      console.log('handle 1 triggered')
    },
  },
}

當然肯定也會有開發(fā)者會覺得這樣選擇多是個好事,選擇適合自己的就好,但筆者還是認為這種寫法對于初學者來說不是那么友好,有些過于復雜化,如果一個用法可以適應各種各樣的場景,豈不是更妙?

TIP

另外需要注意的是,不能使用箭頭函數(shù)來定義 Watcher 函數(shù) (例如 searchQuery: newValue => this.updateAutocomplete(newValue) )。

因為箭頭函數(shù)綁定了父級作用域的上下文,所以 this 將不會按照期望指向組件實例, this.updateAutocomplete 將是 undefined 。

Vue 2 也可以通過 this.$watch() 這個 API 的用法來實現(xiàn)對某個數(shù)據(jù)的偵聽,它接受三個參數(shù): source 、 callback 和 options 。

export default {
  data() {
    return {
      a: 1,
    }
  },
  // 生命周期鉤子
  mounted() {
    this.$watch('a', (newVal, oldVal) => {
      // ...
    })
  },
}

由于 this.$watch 的用法和 Vue 3 比較接近,所以這里不做過多的回顧,請直接看 了解 Vue 3 部分。

了解 Vue 3

在 Vue 3 的組合式 API 寫法, watch 是一個可以接受 3 個參數(shù)的函數(shù)(保留了 Vue 2 的 this.$watch 這種用法),在使用層面上簡單了很多。

import { watch } from 'vue'

// 一個用法走天下
watch(
  source, // 必傳,要偵聽的數(shù)據(jù)源
  callback // 必傳,偵聽到變化后要執(zhí)行的回調(diào)函數(shù)
  // options // 可選,一些偵聽選項
)

下面的內(nèi)容都基于 Vue 3 的組合式 API 用法展開講解。

API 的 TS 類型

在了解用法之前,先對它的 TS 類型聲明做一個簡單的了解, watch 作為組合式 API ,根據(jù)使用方式有兩種類型聲明:

1.基礎用法的 TS 類型,詳見 基礎用法 部分

// watch 部分的 TS 類型
// ...
export declare function watch<T, Immediate extends Readonly<boolean> = false>(
  source: WatchSource<T>,
  cb: WatchCallback<T, Immediate extends true ? T | undefined : T>,
  options?: WatchOptions<Immediate>
): WatchStopHandle
// ...

2.批量偵聽的 TS 類型,詳見 批量偵聽 部分

// watch 部分的 TS 類型
// ...
export declare function watch<
  T extends MultiWatchSources,
  Immediate extends Readonly<boolean> = false
>(
  sources: [...T],
  cb: WatchCallback<MapSources<T, false>, MapSources<T, Immediate>>,
  options?: WatchOptions<Immediate>
): WatchStopHandle

// MultiWatchSources 是一個數(shù)組
declare type MultiWatchSources = (WatchSource<unknown> | object)[]
// ...

但是不管是基礎用法還是批量偵聽,可以看到這個 API 都是接受三個入?yún)ⅲ?/p>

并返回一個可以用來停止偵聽的函數(shù)(詳見:停止偵聽)。

要偵聽的數(shù)據(jù)源

在上面 API 的 TS 類型 已經(jīng)對 watch API 的組成有一定的了解了,這里先對數(shù)據(jù)源的類型和使用限制做下說明。

TIP

如果不提前了解,在使用的過程中可能會遇到 “偵聽了但沒有反應” 的情況出現(xiàn)。

另外,這部分內(nèi)容會先圍繞基礎用法展開說明,批量偵聽會在 批量偵聽 部分單獨說明。

watch API 的第 1 個參數(shù) source 是要偵聽的數(shù)據(jù)源,它的 TS 類型如下:

// watch 第 1 個入?yún)⒌?TS 類型
// ...
export declare type WatchSource<T = any> = Ref<T> | ComputedRef<T> | (() => T)
// ...

可以看到能夠用于偵聽的數(shù)據(jù),是通過 響應式 API 定義的變量( Ref ),或者是一個 計算數(shù)據(jù) ( ComputedRef ),或者是一個 getter 函數(shù) ( () => T )。

所以要想定義的 watch 能夠做出預期的行為,數(shù)據(jù)源必須具備響應性或者是一個 getter ,如果只是通過 let 定義一個普通變量,然后去改變這個變量的值,這樣是無法偵聽的。

TIP

如果要偵聽響應式對象里面的某個值(這種情況下對象本身是響應式,
但它的 property 不是),
需要寫成 getter 函數(shù),
簡單的說就是需要寫成有返回值的函數(shù),
這個函數(shù) return 要偵聽的數(shù)據(jù), e.g. () => foo.bar ,
可以結合下方 基礎用法 的例子一起理解。

偵聽后的回調(diào)函數(shù)

在上面 API 的 TS 類型 介紹了 watch API 的組成,和數(shù)據(jù)源一樣,先了解一下回調(diào)函數(shù)的定義。

TIP

和數(shù)據(jù)源部分一樣,回調(diào)函數(shù)的內(nèi)容也是會先圍繞基礎用法展開說明,
批量偵聽會在 批量偵聽 部分單獨說明。

watch API 的第 2 個參數(shù) callback 是偵聽到數(shù)據(jù)變化時要做出的行為,它的 TS 類型如下:

// watch 第 2 個入?yún)⒌?TS 類型
// ...
export declare type WatchCallback<V = any, OV = any> = (
  value: V,
  oldValue: OV,
  onCleanup: OnCleanup
) => any
// ...

乍一看它有三個參數(shù),但實際上這些參數(shù)不是自己定義的,而是 watch API 傳給的,所以不管用或者不用,它們都在那里:

注意:第一個參數(shù)是新值,第二個才是原來的舊值!

如同其他 JS 函數(shù),在使用 watch 的回調(diào)函數(shù)時,可以對這三個參數(shù)任意命名,比如把 value 命名為覺得更容易理解的 newValue 。

TIP

如果偵聽的數(shù)據(jù)源是一個 引用類型 時( e.g. Object 、 Array 、 Date … ), 
value 和 oldValue 是完全相同的,因為指向同一個對象。

另外,默認情況下,watch 是惰性的,也就是只有當被偵聽的數(shù)據(jù)源發(fā)生變化時才執(zhí)行回調(diào)。

基礎用法

來到這里,對 2 個必傳的參數(shù)都有一定的了解了,先看看基礎的用法,也就是日常最常編寫的方案,只需要先關注前 2 個必傳的參數(shù)。

// 不要忘了導入要用的 API
import {defineComponent,reactive ,watch} from 'vue'
export default defineComponent({
 setup(){
 //定義一個響應式數(shù)據(jù)
 const userInfo=reactive({
 name:'Petter',
 age:18
 })
 //2s后改變數(shù)據(jù)
 setTimeout(()=>{
 userInfo.name='tom'
 },2000)
 /**
     * 可以直接偵聽這個響應式對象
     * callback 的參數(shù)如果不用可以不寫
     */
   watch(userInfo,()=>{
       console.log('偵聽整個 userInfo ', userInfo.name)
   })
      /**
     * 也可以偵聽對象里面的某個值
     * 此時數(shù)據(jù)源需要寫成 getter 函數(shù)
     */
    watch(
    //數(shù)據(jù)源,getter形式
    ()=>userInfo.name,
    // 回調(diào)函數(shù) callback
    (newValue, oldValue) => {
        console.log('只偵聽 name 的變化 ', userInfo.name)
        console.log('打印變化前后的值', { oldValue, newValue })
      }
    )
 }
})

一般的業(yè)務場景,基礎用法足以面對。

如果有多個數(shù)據(jù)源要偵聽,并且偵聽到變化后要執(zhí)行的行為一樣,那么可以使用 批量偵聽 。

特殊的情況下,可以搭配 偵聽的選項 做一些特殊的用法,詳見下面部分的內(nèi)容。

批量偵聽

如果有多個數(shù)據(jù)源要偵聽,并且偵聽到變化后要執(zhí)行的行為一樣,第一反應可能是這樣來寫:

1.抽離相同的處理行為為公共函數(shù)

2.然后定義多個偵聽操作,傳入這個公共函數(shù)

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

export default defineComponent({
  setup() {
    const message = ref<string>('')
    const index = ref<number>(0)

    // 2s后改變數(shù)據(jù)
    setTimeout(() => {
      // 來到這里才會觸發(fā) watch 的回調(diào)
      message.value = 'Hello World!'
      index.value++
    }, 2000)

    // 抽離相同的處理行為為公共函數(shù)
    const handleWatch = (
      newValue: string | number,
      oldValue: string | number
    ): void => {
      console.log({ newValue, oldValue })
    }

    // 然后定義多個偵聽操作,傳入這個公共函數(shù)
    watch(message, handleWatch)
    watch(index, handleWatch)
  },
})

這樣寫其實沒什么問題,不過除了抽離公共代碼的寫法之外, watch API 還提供了一個批量偵聽的用法,和 基礎用法 的區(qū)別在于,數(shù)據(jù)源和回調(diào)參數(shù)都變成了數(shù)組的形式。

數(shù)據(jù)源:以數(shù)組的形式傳入,里面每一項都是一個響應式數(shù)據(jù)。

回調(diào)參數(shù):原來的 value 和 newValue 也都變成了數(shù)組,每個數(shù)組里面的順序和數(shù)據(jù)源數(shù)組排序一致。

可以看下面的這個例子更為直觀:

import { defineComponent, ref, watch } from 'vue'
export default defineComponent({
    setup(){
      //定義多個數(shù)據(jù)源
      const message = ref<string>('')
      const index = ref<number>(0)

      //2s后改變數(shù)據(jù)
      setTimeout(()=>{
       message.value = 'Hello World!'
       index.value++
      },2000)
      watch(
       //數(shù)據(jù)源改成了數(shù)組
       [message, index],
       //回調(diào)的入?yún)⒁沧兂闪藬?shù)組,每個數(shù)組里面的順序和數(shù)據(jù)源數(shù)組排序一致
       ([newMessage, newIndex], [oldMessage, oldIndex])=>{
         console.log('message 的變化', { newMessage, oldMessage })
        console.log('index 的變化', { newIndex, oldIndex })
       }
       
      )
    }
})

什么情況下可能會用到批量偵聽呢?比如一個子組件有多個 props ,當有任意一個 prop 發(fā)生變化時,都需要執(zhí)行初始化函數(shù)重置組件的狀態(tài),那么這個時候就可以用上這個功能啦!

TIP

在適當?shù)臉I(yè)務場景,
也可以使用 watchEffect 來完成批量偵聽,
但請留意 功能區(qū)別 部分的說明。

偵聽的選項

在 API 的 TS 類型 里提到, watch API 還接受第 3 個參數(shù) options ,可選的一些偵聽選項。

它的 TS 類型如下:

// watch 第 3 個入?yún)⒌?TS 類型
// ...
export declare interface WatchOptions<Immediate = boolean>
  extends WatchOptionsBase {
  immediate?: Immediate
  deep?: boolean
}
// ...

// 繼承的 base 類型
export declare interface WatchOptionsBase extends DebuggerOptions {
  flush?: 'pre' | 'post' | 'sync'
}
// ...

// 繼承的 debugger 選項類型
export declare interface DebuggerOptions {
  onTrack?: (event: DebuggerEvent) => void
  onTrigger?: (event: DebuggerEvent) => void
}
// ...

options 是一個對象的形式傳入,有以下幾個選項:

其中 onTrack 和 onTrigger 的 e 是 debugger 事件,建議在回調(diào)內(nèi)放置一個 debugger 語句 以調(diào)試依賴,這兩個選項僅在開發(fā)模式下生效。

TIP

deep 默認是 false ,
但是在偵聽 reactive 對象或數(shù)組時,會默認為 true ,
詳見 偵聽選項之 deep。

偵聽選項之 deep

deep 選項接受一個布爾值,可以設置為 true 開啟深度偵聽,或者是 false 關閉深度偵聽,默認情況下這個選項是 false 關閉深度偵聽的,但也存在特例。

設置為 false 的情況下,如果直接偵聽一個響應式的 引用類型 數(shù)據(jù)(e.g. Object 、 Array … ),雖然它的屬性的值有變化,但對其本身來說是不變的,所以不會觸發(fā) watch 的 callback 。

下面是一個關閉了深度偵聽的例子:

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

export default defineComponent({
  setup() {
    // 定義一個響應式數(shù)據(jù),注意用的是 ref 來定義
    const nums = ref<number[]>([])

    // 2s后給這個數(shù)組添加項目
    setTimeout(() => {
      nums.value.push(1)

      // 可以打印一下,確保數(shù)據(jù)確實變化了
      console.log('修改后', nums.value)
    }, 2000)

    // 但是這個 watch 不會按預期執(zhí)行
    watch(
      nums,
      // 這里的 callback 不會被觸發(fā)
      () => {
        console.log('觸發(fā)偵聽', nums.value)
      },
      // 因為關閉了 deep
      {
        deep: false,
      }
    )
  },
})

類似這種情況,需要把 deep 設置為 true 才可以觸發(fā)偵聽。

可以看到上面的例子特地用了 ref API ,這是因為通過 reactive API 定義的對象無法將 deep 成功設置為 false (這一點在目前的官網(wǎng)文檔未找到說明,最終是在 watch API 的源碼 上找到了答案)。

// ...
if (isReactive(source)) {
  getter = () => source
  deep = true // 被強制開啟了
}
// ...

這個情況就是上面所說的 “特例” ,可以通過 isReactive API 來判斷是否需要手動開啟深度偵聽。

// 導入 isReactive API
import { defineComponent, isReactive, reactive, ref } from 'vue'

export default defineComponent({
  setup() {
    // 偵聽這個數(shù)據(jù)時,會默認開啟深度偵聽
    const foo = reactive({
      name: 'Petter',
      age: 18,
    })
    console.log(isReactive(foo)) // true

    // 偵聽這個數(shù)據(jù)時,不會默認開啟深度偵聽
    const bar = ref({
      name: 'Petter',
      age: 18,
    })
    console.log(isReactive(bar)) // false
  },
})

偵聽選項之 immediate

在 偵聽后的回調(diào)函數(shù) 部分有了解過, watch 默認是惰性的,也就是只有當被偵聽的數(shù)據(jù)源發(fā)生變化時才執(zhí)行回調(diào)。

這句話是什么意思呢?來看一下這段代碼,為了減少 deep 選項的干擾,換一個類型,換成 string 數(shù)據(jù)來演示,請留意注釋:

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

export default defineComponent({
  setup() {
    // 這個時候不會觸發(fā) watch 的回調(diào)
    const message = ref<string>('')

    // 2s后改變數(shù)據(jù)
    setTimeout(() => {
      // 來到這里才會觸發(fā) watch 的回調(diào)
      message.value = 'Hello World!'
    }, 2000)

    watch(message, () => {
      console.log('觸發(fā)偵聽', message.value)
    })
  },
})

可以看到,數(shù)據(jù)在初始化的時候并不會觸發(fā)偵聽回調(diào),如果有需要的話,通過 immediate 選項來讓它直接觸發(fā)。

immediate 選項接受一個布爾值,默認是 false ,可以設置為 true 讓回調(diào)立即執(zhí)行。

改成這樣,請留意高亮的代碼部分和新的注釋:

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

export default defineComponent({
  setup() {
    // 這一次在這里可以會觸發(fā) watch 的回調(diào)了
    const message = ref<string>('')

    // 2s后改變數(shù)據(jù)
    setTimeout(() => {
      // 這一次,這里是第二次觸發(fā) watch 的回調(diào),不再是第一次
      message.value = 'Hello World!'
    }, 2000)

    watch(
      message,
      () => {
        console.log('觸發(fā)偵聽', message.value)
      },
      // 設置 immediate 選項
      {
        immediate: true,
      }
    )
  },
})

注意,在帶有 immediate 選項時,不能在第一次回調(diào)時取消該數(shù)據(jù)源的偵聽,詳見 停止偵聽 部分。

偵聽選項之 flush

flush 選項是用來控制 偵聽回調(diào) 的調(diào)用時機,接受指定的字符串,可選值如下,默認是 ‘pre’ 。

對于 ‘pre’ 和 ‘post’ ,回調(diào)使用隊列進行緩沖?;卣{(diào)只被添加到隊列中一次。

即使觀察值變化了多次,值的中間變化將被跳過,不會傳遞給回調(diào),這樣做不僅可以提高性能,還有助于保證數(shù)據(jù)的一致性。

更多關于 flush 的信息,請參閱 回調(diào)的觸發(fā)時機 。

停止偵聽

如果在 setup 或者 script-setup 里使用 watch 的話, 組件被卸載 的時候也會一起被停止,一般情況下不太需要關心如何停止偵聽。

不過有時候可能想要手動取消, Vue 3 也提供了方法。

TIP

隨著組件被卸載一起停止的前提是,偵聽器必須是 同步語句 創(chuàng)建的,
這種情況下偵聽器會綁定在當前組件上。

如果放在 setTimeout 等 異步函數(shù) 里面創(chuàng)建,
則不會綁定到當前組件,因此組件卸載的時候不會一起停止該偵聽器,
這種時候就需要手動停止偵聽。

在 API 的 TS 類型 有提到,當在定義一個 watch 行為的時候,它會返回一個用來停止偵聽的函數(shù)。

這個函數(shù)的 TS 類型如下:

export declare type WatchStopHandle = () => void

用法很簡單,做一下簡單了解即可:

// 定義一個取消觀察的變量,它是一個函數(shù)
const unwatch = watch(message, () => {
  // ...
})

// 在合適的時期調(diào)用它,可以取消這個偵聽
unwatch()

但是也有一點需要注意的是,如果啟用了 immediate 選項 ,不能在第一次觸發(fā)偵聽回調(diào)時執(zhí)行它。

// 注意:這是一段錯誤的代碼,運行會報錯
const unwatch = watch(
  message,
  // 偵聽的回調(diào)
  () => {
    // ...
    // 在這里調(diào)用會有問題 ?
    unwatch()
  },
  // 啟用 immediate 選項
  {
    immediate: true,
  }
)

會收獲一段報錯,告訴 unwatch 這個變量在初始化前無法被訪問:

Uncaught ReferenceError: Cannot access 'unwatch' before initialization

目前有兩種方案可以讓實現(xiàn)這個操作:

方案一:使用 var 并判斷變量類型,利用 var 的變量提升 來實現(xiàn)目的。

// 這里改成 var ,不要用 const 或 let
var unwatch = watch(
  message,
  // 偵聽回調(diào)
  () => {
    // 這里加一個判斷,是函數(shù)才執(zhí)行它
    if (typeof unwatch === 'function') {
      unwatch()
    }
  },
  // 偵聽選項
  {
    immediate: true,
  }
)

不過 var 已經(jīng)屬于過時的語句了,建議用方案二的 let 。

方案二:使用 let 并判斷變量類型。

// 如果不想用 any ,可以導入 TS 類型
import type { WatchStopHandle } from 'vue'

// 這里改成 let ,但是要另起一行,先定義,再賦值
let unwatch: WatchStopHandle
unwatch = watch(
  message,
  // 偵聽回調(diào)
  () => {
    // 這里加一個判斷,是函數(shù)才執(zhí)行它
    if (typeof unwatch === 'function') {
      unwatch()
    }
  },
  // 偵聽選項
  {
    immediate: true,
  }
)

偵聽效果清理

在 偵聽后的回調(diào)函數(shù) 部分提及到一個參數(shù) onCleanup ,它可以幫注冊一個清理函數(shù)。

有時 watch 的回調(diào)會執(zhí)行異步操作,當 watch 到數(shù)據(jù)變更的時候,需要取消這些操作,這個函數(shù)的作用就用于此,會在以下情況調(diào)用這個清理函數(shù):

watcher 即將重新運行的時候

watcher 被停止(組件被卸載或者被手動 停止偵聽 )

TS 類型:

declare type OnCleanup = (cleanupFn: () => void) => void

用法方面比較簡單,傳入一個回調(diào)函數(shù)運行即可,不過需要注意的是,需要在停止偵聽之前注冊好清理行為,否則不會生效。

在 停止偵聽 里的最后一個 immediate 例子的基礎上繼續(xù)添加代碼,請注意注冊的時機:

let unwatch: WatchStopHandle
unwatch = watch(
  message,
  (newValue, oldValue, onCleanup) => {
    // 需要在停止偵聽之前注冊好清理行為
    onCleanup(() => {
      console.log('偵聽清理ing')
      // 根據(jù)實際的業(yè)務情況定義一些清理操作 ...
    })
    // 然后再停止偵聽
    if (typeof unwatch === 'function') {
      unwatch()
    }
  },
  {
    immediate: true,
  }
)

watchEffect

如果一個函數(shù)里包含了多個需要偵聽的數(shù)據(jù),一個一個數(shù)據(jù)去偵聽太麻煩了,在 Vue 3 ,可以直接使用 watchEffect API 來簡化的操作。

API 的 TS 類型

這個 API 的類型如下,使用的時候需要傳入一個副作用函數(shù)(相當于 watch 的 偵聽后的回調(diào)函數(shù) ),也可以根據(jù)的實際情況傳入一些可選的 偵聽選項 。

和 watch API 一樣,它也會返回一個用于 停止偵聽 的函數(shù)。

// watchEffect 部分的 TS 類型
// ...
export declare type WatchEffect = (onCleanup: OnCleanup) => void

export declare function watchEffect(
  effect: WatchEffect,
  options?: WatchOptionsBase
): WatchStopHandle
// ...

副作用函數(shù)也會傳入一個清理回調(diào)作為參數(shù),和 watch 的 偵聽效果清理 一樣的用法。

可以理解為它是一個簡化版的 watch ,具體簡化在哪里呢?請看下面的用法示例。

用法示例

它立即執(zhí)行傳入的一個函數(shù),同時響應式追蹤其依賴,并在其依賴變更時重新運行該函數(shù)。

import { defineComponent, ref, watchEffect } from 'vue'

export default defineComponent({
  setup() {
    // 單獨定義兩個數(shù)據(jù),后面用來分開改變數(shù)值
    const name = ref<string>('Petter')
    const age = ref<number>(18)

    // 定義一個調(diào)用這兩個數(shù)據(jù)的函數(shù)
    const getUserInfo = (): void => {
      console.log({
        name: name.value,
        age: age.value,
      })
    }

    // 2s后改變第一個數(shù)據(jù)
    setTimeout(() => {
      name.value = 'Tom'
    }, 2000)

    // 4s后改變第二個數(shù)據(jù)
    setTimeout(() => {
      age.value = 20
    }, 4000)

    // 直接偵聽調(diào)用函數(shù),在每個數(shù)據(jù)產(chǎn)生變化的時候,它都會自動執(zhí)行
    watchEffect(getUserInfo)
  },
})

和 watch 的區(qū)別

雖然理論上 watchEffect 是 watch 的一個簡化操作,可以用來代替 批量偵聽 ,但它們也有一定的區(qū)別:

1.watch 可以訪問偵聽狀態(tài)變化前后的值,而 watchEffect 沒有。

2.watch 是在屬性改變的時候才執(zhí)行,而 watchEffect 則默認會執(zhí)行一次,然后在屬性改變的時候也會執(zhí)行。

第二點的意思,看下面這段代碼可以有更直觀的理解:

使用 watch :

export default defineComponent({
  setup() {
    const foo = ref<string>('')

    setTimeout(() => {
      foo.value = 'Hello World!'
    }, 2000)

    function bar() {
      console.log(foo.value)
    }

    // 使用 watch 需要先手動執(zhí)行一次
    bar()

    // 然后當 foo 有變動時,才會通過 watch 來執(zhí)行 bar()
    watch(foo, bar)
  },
})

使用 watchEffect :

export default defineComponent({
  setup() {
    const foo = ref<string>('')

    setTimeout(() => {
      foo.value = 'Hello World!'
    }, 2000)

    function bar() {
      console.log(foo.value)
    }

    // 可以通過 watchEffect 實現(xiàn) bar() + watch(foo, bar) 的效果
    watchEffect(bar)
  },
})

可用的偵聽選項

雖然用法和 watch 類似,但也簡化了一些選項,它的偵聽選項 TS 類型如下:

// 只支持 base 類型
export declare interface WatchOptionsBase extends DebuggerOptions {
  flush?: 'pre' | 'post' | 'sync'
}
// ...

// 繼承的 debugger 選項類型
export declare interface DebuggerOptions {
  onTrack?: (event: DebuggerEvent) => void
  onTrigger?: (event: DebuggerEvent) => void
}
// ...

對比 watch API ,它不支持 deep 和 immediate ,請記住這一點,其他的用法是一樣的。

flush 選項的使用詳見 偵聽選項之 flush ,onTrack 和 onTrigger 詳見 偵聽的選項 部分內(nèi)容。

watchPostEffect

watchEffect API 使用 flush: ‘post’ 選項時的別名,具體區(qū)別詳見 偵聽選項之 flush 部分。

TIP

Vue v3.2.0 及以上版本才支持該 API 。

watchSyncEffect

watchEffect API 使用 flush: ‘sync’ 選項時的別名,具體區(qū)別詳見 偵聽選項之 flush 部分。

TIP

Vue v3.2.0 及以上版本才支持該 API 。

總結

到此這篇關于VUE3數(shù)據(jù)的偵聽的文章就介紹到這了,更多相關VUE3數(shù)據(jù)偵聽內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • nuxt.js添加環(huán)境變量,區(qū)分項目打包環(huán)境操作

    nuxt.js添加環(huán)境變量,區(qū)分項目打包環(huán)境操作

    這篇文章主要介紹了nuxt.js添加環(huán)境變量,區(qū)分項目打包環(huán)境操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-11-11
  • 如何巧用Vue.extend繼承組件實現(xiàn)el-table雙擊可編輯(不使用v-if、v-else)

    如何巧用Vue.extend繼承組件實現(xiàn)el-table雙擊可編輯(不使用v-if、v-else)

    這篇文章主要給大家介紹了關于如何巧用Vue.extend繼承組件實現(xiàn)el-table雙擊可編輯的相關資料,不使用v-if、v-else,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下
    2022-06-06
  • Nuxt不同環(huán)境如何區(qū)分的方法

    Nuxt不同環(huán)境如何區(qū)分的方法

    在一般情況下,我們的項目肯定需要區(qū)分不同環(huán)境,那么Nuxt提供給我們這樣的基本能力了么,下面我們就一起來了解一下
    2021-05-05
  • vue中@click綁定多個事件問題(教你避坑)

    vue中@click綁定多個事件問題(教你避坑)

    這篇文章主要介紹了vue中@click綁定多個事件問題(教你避坑),具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-08-08
  • vue ssr 指南詳讀

    vue ssr 指南詳讀

    這篇文章主要介紹了vue ssr 指南詳讀,詳細的介紹了什么是SSR以及如何使用,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-06-06
  • vue報錯Failed to execute 'appendChild' on 'Node'解決

    vue報錯Failed to execute 'appendChild&apos

    這篇文章主要為大家介紹了vue報錯Failed to execute 'appendChild' on 'Node'解決方法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-11-11
  • 詳解Vue組件如何正確引用和使用外部方法

    詳解Vue組件如何正確引用和使用外部方法

    在開發(fā)Vue應用時,我們經(jīng)常需要在多個組件中復用一些通用的函數(shù)或方法,這些函數(shù)可能是我們自己編寫的工具函數(shù),也可能是從第三方庫中導入的,下面我們就來看看如何正確引用和使用外部方法吧
    2024-01-01
  • vue的axios和mock.js你了解嗎

    vue的axios和mock.js你了解嗎

    這篇文章主要為大家詳細介紹了vue的axios和mock.js,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-02-02
  • vue2使用wangeditor實現(xiàn)數(shù)學公式和富文本編輯器

    vue2使用wangeditor實現(xiàn)數(shù)學公式和富文本編輯器

    這篇文章主要為大家詳細介紹了vue2如何使用wangeditor實現(xiàn)數(shù)學公式和富文本編輯器功能,文中的示例代碼講解詳細,感興趣的小伙伴可以了解一下
    2023-12-12
  • vue-jsonp的使用及說明

    vue-jsonp的使用及說明

    這篇文章主要介紹了vue-jsonp的使用及說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-12-12

最新評論