Vue3中watch與watchEffect使用方法詳解
一、監(jiān)聽器的基本概念
在Vue3中,watch
和watchEffect
都是用于監(jiān)聽數(shù)據(jù)變化并執(zhí)行副作用的API,但它們的使用方式和適用場景有所不同。
- watch:需要顯式指定監(jiān)聽的數(shù)據(jù)源,惰性執(zhí)行(默認數(shù)據(jù)變化時才執(zhí)行),可以獲取新舊值
- watchEffect:自動收集依賴,立即執(zhí)行,無法獲取舊值
二、watch的使用方法
2.1 基礎(chǔ)用法:監(jiān)聽單個ref數(shù)據(jù)
<template> <div> <p>計數(shù)器: {{ count }}</p> <button @click="count++">增加</button> </div> </template> <script setup> import { ref, watch } from 'vue' // 創(chuàng)建響應(yīng)式數(shù)據(jù) const count = ref(0) // 監(jiān)聽count變化 // 第一個參數(shù):要監(jiān)聽的數(shù)據(jù)源 // 第二個參數(shù):回調(diào)函數(shù),接收新值和舊值 watch(count, (newValue, oldValue) => { console.log(`count從${oldValue}變?yōu)?{newValue}`) }) </script>
2.2 監(jiān)聽多個數(shù)據(jù)源【監(jiān)聽多個數(shù)據(jù),用數(shù)組形式傳入】
import { ref, watch } from 'vue' const firstName = ref('張') const lastName = ref('三') // 監(jiān)聽多個數(shù)據(jù),用數(shù)組形式傳入 watch([firstName, lastName], ([newFirst, newLast], [oldFirst, oldLast]) => { console.log(`姓名從${oldFirst}${oldLast}變?yōu)?{newFirst}${newLast}`) })
2.3 監(jiān)聽對象屬性【監(jiān)聽對象的某個屬性,使用getter函數(shù)】
import { reactive, watch } from 'vue' const user = reactive({ name: '張三', age: 20 }) // 監(jiān)聽對象的某個屬性,使用getter函數(shù) watch( () => user.age, // getter函數(shù),返回要監(jiān)聽的屬性 (newAge, oldAge) => { console.log(`年齡從${oldAge}變?yōu)?{newAge}`) } )
2.4 深度監(jiān)聽
當(dāng)監(jiān)聽對象或數(shù)組時,默認情況下watch不會監(jiān)聽內(nèi)部屬性變化,需要使用deep: true
開啟深度監(jiān)聽:
import { ref, watch } from 'vue' const user = ref({ name: '張三', address: { city: '北京' } }) // 深度監(jiān)聽對象內(nèi)部變化 watch( user, (newVal, oldVal) => { console.log('用戶信息變化:', newVal)}, { deep: true } // 開啟深度監(jiān)聽 ) // 修改深層屬性會觸發(fā)監(jiān)聽 user.value.address.city = '上海'
2.5 立即執(zhí)行
默認情況下,watch是惰性的,只有數(shù)據(jù)變化時才執(zhí)行。使用immediate: true
可以讓它在初始化時立即執(zhí)行:
watch( count, (newValue, oldValue) => { console.log(`count變化: ${newValue}`) }, { immediate: true } // 立即執(zhí)行 )
三、watchEffect的使用方法【可以不用指定監(jiān)聽的數(shù)據(jù)】
3.1 基礎(chǔ)用法
watchEffect會自動收集函數(shù)內(nèi)使用的響應(yīng)式數(shù)據(jù)作為依賴:
自動追蹤所有響應(yīng)式依賴, 每次依賴變更都會執(zhí)行此函數(shù)
<template> <div> <p>計數(shù)器: {{ count }}</p> <button @click="count++">增加</button> </div> </template> <script setup> import { ref, watchEffect } from 'vue' const count = ref(0) // watchEffect會自動收集依賴 // 1. 初始化時立即執(zhí)行一次 // 2. 當(dāng)函數(shù)內(nèi)依賴的響應(yīng)式數(shù)據(jù)變化時重新執(zhí)行 watchEffect( () => {console.log(`count的值是: ${count.value}`)} ) </script>
3.2 停止監(jiān)聽
watchEffect返回一個停止函數(shù),調(diào)用它可以停止監(jiān)聽:
import { ref, watchEffect } from 'vue' const count = ref(0) // 獲取停止函數(shù) const stop = watchEffect(() => { console.log(`count: ${count.value}`) }) // 5秒后停止監(jiān)聽 setTimeout(() => { stop() console.log('已停止監(jiān)聽') }, 5000)
3.3 清理副作用
watchEffect的回調(diào)函數(shù)可以返回一個清理函數(shù),在下次執(zhí)行前或停止監(jiān)聽時調(diào)用:
watchEffect((onInvalidate) => { // 模擬異步操作 const timer = setTimeout(() => { console.log('異步操作完成') }, 1000) // 清理函數(shù),在下次執(zhí)行前或停止監(jiān)聽時調(diào)用 onInvalidate(() => { clearTimeout(timer) console.log('清理定時器') }) })
四、watch與watchEffect的區(qū)別
特性 | watch | watchEffect |
---|---|---|
依賴收集 | 需要顯式指定監(jiān)聽源 | 自動收集函數(shù)內(nèi)的響應(yīng)式依賴 |
執(zhí)行時機 | 默認惰性執(zhí)行(數(shù)據(jù)變化時) | 立即執(zhí)行,然后響應(yīng)式追蹤 |
新舊值 | 可以獲取新值和舊值 | 只能獲取新值 |
適用場景 | 需要知道數(shù)據(jù)變化前后的值 | 只需響應(yīng)數(shù)據(jù)變化,不需要舊值 |
控制粒度 | 精確控制監(jiān)聽源 | 自動追蹤所有依賴 |
五、高級用法
5.1 監(jiān)聽執(zhí)行時機控制
使用flush
選項控制回調(diào)執(zhí)行時機:
watch( count, () => { // DOM更新后執(zhí)行 }, { flush: 'post' } // 'pre'(默認) | 'post' | 'sync' )
5.2 調(diào)試監(jiān)聽器
使用onTrack
和onTrigger
選項調(diào)試依賴:
watch( count, () => { console.log('count變化了') }, { onTrack(e) { console.log('依賴被追蹤:', e) }, onTrigger(e) { console.log('監(jiān)聽器被觸發(fā):', e) } } )
5.3 暫停與恢復(fù)監(jiān)聽(Vue3.5+)
Vue3.5+版本新增了暫停和恢復(fù)監(jiān)聽的功能:
const { pause, resume } = watch(count, () => { console.log('count變化了') }) // 暫停監(jiān)聽 pause() // 恢復(fù)監(jiān)聽 resume()
六、實戰(zhàn)示例
6.1 表單驗證(使用watch)
import { ref, watch } from 'vue' const username = ref('') const errorMessage = ref('') // 監(jiān)聽用戶名變化進行驗證 watch( username, (newVal) => { if (newVal.length < 3) { errorMessage.value = '用戶名至少3個字符' } else { errorMessage.value = '' } }, { immediate: true } // 初始化時驗證 )
6.2 數(shù)據(jù)加載與清理(使用watchEffect)
import { ref, watchEffect } from 'vue' const userId = ref(1) const userData = ref(null) watchEffect(async (onInvalidate) => { // 加載數(shù)據(jù) const controller = new AbortController() const signal = controller.signal try { const response = await fetch(`/api/user/${userId.value}`, { signal }) userData.value = await response.json() } catch (error) { if (error.name !== 'AbortError') { console.error('加載失敗:', error) } } // 清理函數(shù),取消上一次請求 onInvalidate(() => { controller.abort() }) })
七、總結(jié)
- watch適合需要精細控制監(jiān)聽源、需要新舊值對比或需要延遲執(zhí)行的場景
- watchEffect適合簡單的副作用處理,自動追蹤依賴,代碼更簡潔
- 優(yōu)先使用watchEffect處理簡單邏輯,使用watch處理復(fù)雜場景
- 注意清理副作用,避免內(nèi)存泄漏
- 組件卸載時,同步創(chuàng)建的監(jiān)聽器會自動停止,異步創(chuàng)建的需要手動停止## 八、深入理解與高級技巧
7.1 watch監(jiān)聽reactive對象的注意事項
當(dāng)監(jiān)聽reactive創(chuàng)建的響應(yīng)式對象時,有一些特殊情況需要注意:
import { reactive, watch } from 'vue' const user = reactive({ name: '張三', age: 20 }) // 情況一:直接監(jiān)聽reactive對象 // 此時會自動開啟深度監(jiān)聽,無需設(shè)置deep: true watch(user, (newVal, oldVal) => { console.log('用戶信息變化', newVal) }) // 情況二:監(jiān)聽reactive對象的屬性 // 必須使用getter函數(shù),否則無法觸發(fā)監(jiān)聽 watch( () => user.age, // 正確寫法 (newAge) => { console.log('年齡變化:', newAge) } ) // 錯誤寫法:直接監(jiān)聽屬性無法觸發(fā) watch(user.age, () => { console.log('年齡變化') // 不會執(zhí)行 })
7.2 watchEffect的依賴追蹤細節(jié)
watchEffect的依賴追蹤是動態(tài)的,只追蹤函數(shù)執(zhí)行過程中實際訪問的響應(yīng)式數(shù)據(jù):
import { ref, watchEffect } from 'vue' const a = ref(0) const b = ref(0) watchEffect(() => { console.log('watchEffect執(zhí)行') if (a.value > 5) { console.log('b的值:', b.value) } }) // 初始執(zhí)行: 輸出 "watchEffect執(zhí)行" a.value = 3 // 執(zhí)行: 輸出 "watchEffect執(zhí)行" (a被訪問) b.value = 5 // 不執(zhí)行 (b未被訪問) a.value = 6 // 執(zhí)行: 輸出 "watchEffect執(zhí)行" 和 "b的值: 5" (a和b都被訪問) b.value = 10 // 執(zhí)行: 輸出 "watchEffect執(zhí)行" 和 "b的值: 10" (b現(xiàn)在被訪問了)
7.3 高級調(diào)試技巧
使用onTrack
和onTrigger
選項可以幫助我們調(diào)試監(jiān)聽器的行為:
watch( count, () => { console.log('count變化了') }, { onTrack(e) { // 當(dāng)依賴被追蹤時觸發(fā) console.log(`追蹤到依賴: ${e.target}的${e.key}屬性`) }, onTrigger(e) { // 當(dāng)監(jiān)聽器被觸發(fā)時觸發(fā) console.log(`監(jiān)聽器觸發(fā)原因: ${e.type}`) } } )
7.4 性能優(yōu)化策略
7.4.1 避免不必要的深度監(jiān)聽
深度監(jiān)聽會遞歸遍歷對象的所有屬性,對于大型對象會影響性能:
// 不推薦:深度監(jiān)聽大型對象 watch(largeObject, () => { // ... }, { deep: true }) // 推薦:只監(jiān)聽需要的屬性 watch( () => largeObject.importantProperty, () => { // ... } )
7.4.2 使用防抖/節(jié)流優(yōu)化頻繁觸發(fā)
對于輸入框等頻繁變化的場景,可以結(jié)合防抖/節(jié)流:
import { ref, watchEffect } from 'vue' import { debounce } from 'lodash' const searchInput = ref('') // 使用防抖優(yōu)化搜索請求 const debouncedSearch = debounce(async (value) => { const results = await fetch(`/api/search?q=${value}`) // 處理結(jié)果 }, 300) watchEffect(() => { debouncedSearch(searchInput.value) })
八、常見問題與解決方案
8.1 監(jiān)聽器不觸發(fā)的常見原因
- 監(jiān)聽了非響應(yīng)式數(shù)據(jù)
// 錯誤:監(jiān)聽普通變量 let count = 0 watch(count, () => { /* 不會觸發(fā) */ }) // 正確:監(jiān)聽響應(yīng)式數(shù)據(jù) const count = ref(0) watch(count, () => { /* 會觸發(fā) */ })
- 直接修改數(shù)組索引或長度
const list = ref([1, 2, 3]) // 錯誤:直接修改索引 list.value[0] = 100 // 不會觸發(fā)監(jiān)聽 // 正確:使用數(shù)組方法或set list.value.push(4) // 會觸發(fā) list.value.splice(0, 1, 100) // 會觸發(fā)
- 監(jiān)聽對象新增屬性
const user = reactive({ name: '張三' }) // 錯誤:直接添加屬性 user.age = 20 // 默認不會觸發(fā)監(jiān)聽 // 正確:使用Vue.set或重新賦值 user.age = 20 // 在Vue3中,reactive對象新增屬性會觸發(fā)監(jiān)聽 // 或?qū)τ趓ef對象 user.value = { ...user.value, age: 20 }
8.2 watch與computed的選擇
場景 | 推薦使用 | 原因 |
---|---|---|
數(shù)據(jù)轉(zhuǎn)換/計算 | computed | 緩存結(jié)果,更高效 |
數(shù)據(jù)變化時執(zhí)行異步操作 | watch | 適合處理副作用 |
需要知道數(shù)據(jù)變化前后的值 | watch | computed無法獲取舊值 |
簡單的依賴追蹤 | watchEffect | 代碼更簡潔 |
九、完整實戰(zhàn)案例:搜索功能實現(xiàn)
下面是一個結(jié)合watch、watchEffect和computed的完整搜索功能實現(xiàn):
<template> <div class="search-container"> <input v-model="searchQuery" placeholder="搜索..." @input="handleInput" > <div v-if="isSearching" class="loading">搜索中...</div> <div v-if="errorMessage" class="error">{{ errorMessage }}</div> <ul v-else-if="results.length"> <li v-for="result in results" :key="result.id">{{ result.name }}</li> </ul> <div v-else-if="!isSearching && searchQuery">無結(jié)果</div> </div> </template> <script setup> import { ref, watch, watchEffect, computed, onUnmounted } from 'vue' // 響應(yīng)式數(shù)據(jù) const searchQuery = ref('') const results = ref([]) const isSearching = ref(false) const errorMessage = ref('') const debouncedQuery = ref('') // 防抖處理 let timeoutId = null const handleInput = () => { clearTimeout(timeoutId) timeoutId = setTimeout(() => { debouncedQuery.value = searchQuery.value }, 300) } // 使用watch處理搜索邏輯 watch( debouncedQuery, async (newQuery) => { if (!newQuery.trim()) { results.value = [] return } isSearching.value = true errorMessage.value = '' try { const response = await fetch(`/api/search?q=${encodeURIComponent(newQuery)}`) if (!response.ok) throw new Error('搜索失敗') results.value = await response.json() } catch (err) { errorMessage.value = err.message } finally { isSearching.value = false } }, { immediate: false } ) // 使用watchEffect清理定時器 watchEffect((onInvalidate) => { // 組件卸載時清理定時器 onInvalidate(() => { clearTimeout(timeoutId) }) }) // 清理函數(shù) onUnmounted(() => { clearTimeout(timeoutId) }) </script>
十、總結(jié)與最佳實踐
- 優(yōu)先使用watchEffect:當(dāng)你需要自動追蹤多個依賴,且不需要舊值時
- 使用watch的場景:需要明確監(jiān)聽源、需要舊值、需要延遲執(zhí)行或深度監(jiān)聽
- 性能考量:
- 避免對大型對象使用深度監(jiān)聽
- 對頻繁變化的數(shù)據(jù)使用防抖/節(jié)流
- 及時清理副作用,避免內(nèi)存泄漏
- 調(diào)試技巧:使用onTrack和onTrigger追蹤依賴問題
- 組件卸載:異步創(chuàng)建的監(jiān)聽器需要手動停止
通過合理選擇watch和watchEffect,并遵循最佳實踐,可以寫出更高效、更可維護的Vue3代碼。理解它們的內(nèi)部工作原理和適用場景,將幫助你在不同的業(yè)務(wù)需求中做出正確的技術(shù)選擇。## 十二、底層原理與實現(xiàn)機制
10.1 響應(yīng)式依賴收集流程
Vue3的監(jiān)聽器基于響應(yīng)式系統(tǒng)工作,其核心流程如下:
1. 當(dāng)watch/watchEffect執(zhí)行時,會創(chuàng)建一個"副作用函數(shù)"(effect) 2. 執(zhí)行副作用函數(shù),期間訪問的響應(yīng)式數(shù)據(jù)會被"追蹤"(track) 3. 響應(yīng)式數(shù)據(jù)變化時,會"觸發(fā)"(trigger)相關(guān)的副作用函數(shù)重新執(zhí)行 ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ 響應(yīng)式數(shù)據(jù) │────?│ 依賴追蹤器 │────?│ 副作用函數(shù)隊列 │ └─────────────┘ └─────────────┘ └─────────────┘ ▲ │ │ ▼ └──────────────────────────────────────────┘ (數(shù)據(jù)變化時觸發(fā)副作用執(zhí)行)
10.2 watch與watchEffect的內(nèi)部差異
// watch的簡化實現(xiàn) function watch(source, callback, options) { // 創(chuàng)建getter函數(shù) const getter = isRef(source) ? () => source.value : typeof source === 'function' ? source : () => traverse(source); // 執(zhí)行副作用 let oldValue = undefined; const effect = effectFn(() => getter(), { lazy: true, // 懶執(zhí)行,首次不觸發(fā) scheduler: () => { // 調(diào)度函數(shù) const newValue = getter(); callback(newValue, oldValue); oldValue = newValue; } }); // 初始化 if (options.immediate) { callback(getter(), oldValue); } else { oldValue = effect(); } return () => stop(effect); } // watchEffect的簡化實現(xiàn) function watchEffect(effect, options) { const _effect = effectFn(effect, { lazy: false, // 立即執(zhí)行 scheduler: queueJob, // 默認調(diào)度器 ...options }); return () => stop(_effect); }
十一、API參數(shù)全解析
11.1 watch完整參數(shù)說明
// TypeScript類型定義 function watch<T>( source: WatchSource<T> | WatchSource<T>[], callback: WatchCallback<T>, options?: WatchOptions ): StopHandle interface WatchOptions extends WatchEffectOptions { immediate?: boolean // 是否立即執(zhí)行,默認false deep?: boolean // 是否深度監(jiān)聽,默認false flush?: 'pre' | 'post' | 'sync' // 執(zhí)行時機,默認'pre' once?: boolean // 是否只執(zhí)行一次,Vue3.4+,默認false onTrack?: (event: DebuggerEvent) => void // 依賴追蹤時觸發(fā) onTrigger?: (event: DebuggerEvent) => void // 觸發(fā)更新時觸發(fā) }
11.2 flush選項詳解
取值 | 執(zhí)行時機 | 適用場景 |
---|---|---|
‘pre’ | 組件更新前執(zhí)行 | 需要訪問更新前的DOM |
‘post’ | 組件更新后執(zhí)行 | 需要訪問更新后的DOM |
‘sync’ | 同步執(zhí)行 | 需要立即響應(yīng)數(shù)據(jù)變化 |
// 示例:在DOM更新后執(zhí)行 watch( count, () => { // 此時可以獲取到更新后的DOM console.log('DOM高度:', document.getElementById('content').offsetHeight) }, { flush: 'post' } )
十二、TypeScript高級用法
12.1 類型定義與推斷
import { ref, watch, reactive } from 'vue' // 1. 監(jiān)聽ref const count = ref<number>(0) watch<number>(count, (newVal, oldVal) => { // newVal和oldVal都會被推斷為number類型 }) // 2. 監(jiān)聽reactive對象 interface User { name: string age: number } const user = reactive<User>({ name: '張三', age: 20 }) watch( () => user.age, (newAge: number, oldAge: number) => { // 顯式指定類型 } ) // 3. 監(jiān)聽多個源 watch<[number, string]>( [count, () => user.name], ([newCount, newName], [oldCount, oldName]) => { // 類型安全 } )
12.2 自定義監(jiān)聽器類型
import { ref, watch, WatchSource } from 'vue' // 定義通用監(jiān)聽器類型 type CustomWatcher<T> = ( source: WatchSource<T>, callback: (newVal: T, oldVal: T) => void ) => void // 創(chuàng)建帶類型的監(jiān)聽器 const numberWatcher: CustomWatcher<number> = (source, callback) => { return watch(source, callback) } // 使用 const count = ref(0) numberWatcher(count, (newVal, oldVal) => { // 類型安全 })
十三、調(diào)試與問題診斷
13.1 使用Vue DevTools調(diào)試
Vue DevTools提供了專門的監(jiān)聽器調(diào)試面板:
- 查看監(jiān)聽器列表:在"Components"面板中選擇組件,查看"Watchers"部分
- 觸發(fā)時機分析:使用"Timeline"面板記錄監(jiān)聽器觸發(fā)時間線
- 依賴可視化:查看每個監(jiān)聽器依賴的響應(yīng)式數(shù)據(jù)
13.2 常見問題診斷流程
監(jiān)聽器不觸發(fā)時的排查步驟:
1. 確認監(jiān)聽源是響應(yīng)式數(shù)據(jù) - 使用isRef/isReactive檢查 - 確認不是解構(gòu)后的值 2. 檢查監(jiān)聽路徑是否正確 - 對象屬性需使用getter函數(shù) - 數(shù)組需監(jiān)聽整個數(shù)組或使用正確索引 3. 驗證數(shù)據(jù)確實發(fā)生了變化 - 使用console.log打印數(shù)據(jù) - 確認不是引用類型數(shù)據(jù)的內(nèi)部變化 4. 檢查是否需要深度監(jiān)聽 - 對象/數(shù)組內(nèi)部變化需設(shè)置deep: true 5. 檢查是否有條件執(zhí)行問題 - watchEffect中是否有條件語句導(dǎo)致依賴未被訪問
十四、性能優(yōu)化高級技巧
14.1 精確監(jiān)聽避免過度觸發(fā)
// 不好的做法:監(jiān)聽整個對象 watch( user, () => { // 即使無關(guān)屬性變化也會觸發(fā) }, { deep: true } ) // 好的做法:只監(jiān)聽需要的屬性 watch( () => ({ name: user.name, age: user.age }), ({ name, age }) => { // 只有這兩個屬性變化才觸發(fā) } )
14.2 監(jiān)聽器防抖與節(jié)流
import { ref, watch } from 'vue' import { debounce, throttle } from 'lodash' // 防抖示例 const searchInput = ref('') const debouncedSearch = debounce((value) => { // 搜索邏輯 }, 300) watch(searchInput, debouncedSearch) // 節(jié)流示例 const scrollPosition = ref(0) const throttledScroll = throttle((position) => { // 滾動處理邏輯 }, 100) watch(scrollPosition, throttledScroll)
14.3 大數(shù)據(jù)場景優(yōu)化
對于大型列表或復(fù)雜對象,使用shallowRef
和shallowReactive
減少響應(yīng)式開銷:
import { shallowRef, watch } from 'vue' // 大型數(shù)據(jù)使用shallowRef const largeList = shallowRef([]) // 只監(jiān)聽引用變化,不監(jiān)聽內(nèi)部屬性 watch(largeList, () => { // 只有當(dāng)整個列表被替換時才觸發(fā) })
十五、Vue2遷移指南
15.1 watch選項式API與組合式API對比
Vue2選項式API | Vue3組合式API |
---|---|
javascript watch: { count(newVal, oldVal) { // 處理邏輯 } } | javascript watch(count, (newVal, oldVal) => { // 處理邏輯 }) |
javascript watch: { 'user.name'(newVal) { // 監(jiān)聽嵌套屬性 } } | javascript watch(() => user.name, (newVal) => { // 監(jiān)聽嵌套屬性 }) |
javascript watch: { user: { handler: () => {}, deep: true } } | javascript watch(user, () => {}, { deep: true }) |
15.2 遷移注意事項
- this綁定:Vue3組合式API中沒有this,直接使用響應(yīng)式變量
- 深度監(jiān)聽:Vue3中reactive對象默認深度監(jiān)聽,ref對象需要設(shè)置deep: true
- 數(shù)組監(jiān)聽:Vue3中直接修改數(shù)組索引可以觸發(fā)監(jiān)聽(得益于Proxy)
- **watch方法∗∗:實例方法‘this.watch方法**:實例方法`this.watch方法∗∗:實例方法‘this.watch
替換為
watch`函數(shù)
十六、單元測試示例
使用Jest測試監(jiān)聽器行為:
import { ref, watch, watchEffect } from 'vue' import { mount } from '@vue/test-utils' describe('watch測試', () => { it('基本監(jiān)聽功能', async () => { const count = ref(0) const mockCallback = jest.fn() watch(count, mockCallback) // 初始狀態(tài)不觸發(fā) expect(mockCallback).not.toHaveBeenCalled() // 修改值后觸發(fā) count.value = 1 await Promise.resolve() // 等待微任務(wù)完成 expect(mockCallback).toHaveBeenCalledWith(1, 0) }) it('watchEffect立即執(zhí)行', () => { const mockEffect = jest.fn() watchEffect(mockEffect) // 立即執(zhí)行 expect(mockEffect).toHaveBeenCalled() }) })
十七、總結(jié):監(jiān)聽器選擇決策指南
面對不同場景,如何選擇合適的監(jiān)聽器API:
┌─────────────────────────────────────────────┐ │ 需要知道數(shù)據(jù)變化前后的值 │ │ ↓ │ │ 需要明確指定監(jiān)聽源 │ │ ↓ ┌───────────────┐ │ │ 是────────────?│ watch │?─────────┐ │ ↓ └───────────────┘ │ │ 否 │ │ ↓ ┌───────────────┐ │ │ 需要自動收集依賴 ─────────────?│watchEffect│?─────────┐ │ └───────────────┘ │ │ │ │ 需要緩存計算結(jié)果 ─────────────?│ computed │ └─────────────────────────────────────────────┘
最終建議:
- 簡單場景優(yōu)先使用
watchEffect
,減少樣板代碼 - 需要精確控制時使用
watch
- 純數(shù)據(jù)轉(zhuǎn)換使用
computed
- 始終考慮性能影響,避免過度監(jiān)聽
- 復(fù)雜邏輯拆分到組合式函數(shù)中管理監(jiān)聽器
通過這一章節(jié)的補充,您現(xiàn)在應(yīng)該對Vue3的監(jiān)聽器系統(tǒng)有了全面且深入的理解,能夠在各種場景下選擇合適的API并編寫高效、可維護的代碼。
到此這篇關(guān)于Vue3中watch與watchEffect使用方法的文章就介紹到這了,更多相關(guān)Vue3 watch與watchEffect詳解內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Vue3中Watch、Watcheffect、Computed的使用和區(qū)別解析
- vue3 watch和watchEffect的使用以及有哪些區(qū)別
- Vue3.0監(jiān)聽器watch與watchEffect詳解
- vue3中的watch和watchEffect實例詳解
- 淺談Vue3中watchEffect的具體用法
- Vue3?中?watch?與?watchEffect?區(qū)別及用法小結(jié)
- Vue3中watchEffect高級偵聽器的具體使用
- VUE3中watch和watchEffect的用法詳解
- 一文搞懂Vue3中watchEffect偵聽器的使用
- Vue3中watchEffect和watch的基礎(chǔ)應(yīng)用詳解
相關(guān)文章
vue 插值 v-once,v-text, v-html詳解
這篇文章主要介紹了vue 插值 v-once,v-text, v-html詳解,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-01-01vue項目引入百度地圖BMapGL鼠標(biāo)繪制和BMap輔助工具
這篇文章主要為大家介紹了vue項目引入百度地圖BMapGL鼠標(biāo)繪制和BMap輔助工具的踩坑分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-02-02詳解vue-template-admin三級路由無法緩存的解決方案
這篇文章主要介紹了vue-template-admin三級路由無法緩存的解決方案,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-03-03