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)境操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-11-11如何巧用Vue.extend繼承組件實現(xiàn)el-table雙擊可編輯(不使用v-if、v-else)
這篇文章主要給大家介紹了關于如何巧用Vue.extend繼承組件實現(xiàn)el-table雙擊可編輯的相關資料,不使用v-if、v-else,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下2022-06-06vue報錯Failed to execute 'appendChild&apos
這篇文章主要為大家介紹了vue報錯Failed to execute 'appendChild' on 'Node'解決方法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-11-11vue2使用wangeditor實現(xiàn)數(shù)學公式和富文本編輯器
這篇文章主要為大家詳細介紹了vue2如何使用wangeditor實現(xiàn)數(shù)學公式和富文本編輯器功能,文中的示例代碼講解詳細,感興趣的小伙伴可以了解一下2023-12-12