Vue3中watch無法監(jiān)聽的解決辦法
下面的代碼在對ref實(shí)例賦值完之后。既:
test.value = { name: 1 }
,會發(fā)現(xiàn)不執(zhí)行watch里面的回調(diào)函數(shù)了,這是為什么呢?
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="../../dist/vue.global.js"></script> </head> <body> <div id="app"> </div> <script> var { createApp, ref, watch, onMounted } = Vue; var app = createApp({ setup() { var test = ref({}); onMounted(() => { test.value = { name: 1 } }) setInterval(() => { test.value.name++ }, 3000) watch(test.value, () => { debugger }) return { test, } } }) app.mount('#app') </script> <script> </script> </body> </html>
1:定義ref類型的響應(yīng)式var test = ref({})
, 然后開始執(zhí)行watch(test.value, cb)
函數(shù)
2: 這時(shí)候觸發(fā)了test.value,也就是ref中的get value()
方法,該方法會執(zhí)行trackRefValue(this)
export function trackRefValue(ref: RefBase<any>) { if (shouldTrack && activeEffect) { ref = toRaw(ref) if (__DEV__) { trackEffects(ref.dep || (ref.dep = createDep()), { target: ref, type: TrackOpTypes.GET, key: 'value' }) } else { trackEffects(ref.dep || (ref.dep = createDep())) } } }
- 就是為當(dāng)前ref實(shí)例,收集依賴,但是發(fā)現(xiàn)
shouldTrack
為false,activeEffect
為undefined,所以不執(zhí)行后面的邏輯
3:觸發(fā)ref的get value()
方法之后,開始執(zhí)行watch函數(shù)了
3-1: test.value是響應(yīng)式屬性,所以isReactive(source)
為true, deep為true 如何包裹一層函數(shù)
if (cb && deep) { const baseGetter = getter getter = () => traverse(baseGetter()) }
4: 然后實(shí)例化構(gòu)造函數(shù)const effect = new ReactiveEffect(getter, scheduler)
, 執(zhí)行effect.run()
執(zhí)行getter = () => traverse(baseGetter())
為test.value里面的屬性搜集ReactiveEffect
依賴
5: onMounted之后,直接替換test.value的值,觸發(fā)了set value()
方法
5-1:對新設(shè)置的值,重新定義proxy響應(yīng)式屬性toReactive(newVal)
并且觸發(fā)triggerRefValue(this, newVal)
, 觸發(fā)依賴的執(zhí)行
set value(newVal) { const useDirectValue = this.__v_isShallow || isShallow(newVal) || isReadonly(newVal) newVal = useDirectValue ? newVal : toRaw(newVal) if (hasChanged(newVal, this._rawValue)) { this._rawValue = newVal this._value = useDirectValue ? newVal : toReactive(newVal) triggerRefValue(this, newVal) } }
但是get value()
的時(shí)候,沒有收集到ReactiveEffect
,所以執(zhí)行triggerRefValue(this, newVal)
的時(shí)候,沒有執(zhí)行到watch的回調(diào)函數(shù)
6:后面執(zhí)行setInterval對test.value進(jìn)行賦值的時(shí)候,也沒有更新watch的回調(diào),因?yàn)?code>set value()的時(shí)候 重新執(zhí)行了一次toReactive(newVal)
之前收集的依賴已經(jīng)失效了
7:解決方法
// 方法一 watch(() => test.value, () => { debugger }, { deep: true }) // 方法二 watch(test, () => { debugger }, { deep: true }) // 方法三, 在test.value賦值之后執(zhí)行watch var { createApp, ref, watch, onMounted } = Vue; var app = createApp({ setup() { var test = ref({}); onMounted(() => { test.value = { name: 1 } watch(test.value, () => { debugger }) }) setInterval(() => { test.value.name++ }, 3000) // watch(test.value, () => { // debugger // }) return { test, } } }) app.mount('#app')
這個(gè)寫法,不會一開始就觸發(fā)ref實(shí)例的get value()
方法, 而是在創(chuàng)建 const effect = new ReactiveEffect(getter, scheduler)
,執(zhí)行effect.run() 的時(shí)候,觸發(fā)get value()
方法,搜集依賴
7-1:當(dāng)對test.value = {name: 1}
賦值的時(shí)候,觸發(fā)set value()
方法,就可以觸發(fā)triggerRefValue(this, newVal)
執(zhí)行依賴,從而可以再次對新的值,重新搜集依賴
總結(jié)
普通的寫法進(jìn)行監(jiān)聽,對ref的值進(jìn)行賦值,既:test.value = { name: 1 },在get vlaue()
的時(shí)候,沒有收集 到watch的依賴,在觸發(fā)set value()
的時(shí)候,就沒有再行watch了
而加了函數(shù)包裹test.value,在執(zhí)行effect.run()
的時(shí)候,才會觸發(fā)ref的get value()
, 從而可以執(zhí)行trackRefValue(this)
收集到依賴
watch(() => test.value, () => { debugger }, { deep: true }) export function trackRefValue(ref: RefBase<any>) { if (shouldTrack && activeEffect) { ref = toRaw(ref) if (__DEV__) { trackEffects(ref.dep || (ref.dep = createDep()), { target: ref, type: TrackOpTypes.GET, key: 'value' }) } else { trackEffects(ref.dep || (ref.dep = createDep())) } } }
再觸發(fā)set value()
的時(shí)候,也就可以重新觸發(fā)effect.run()
了
到此這篇關(guān)于Vue3中watch無法監(jiān)聽的解決辦法的文章就介紹到這了,更多相關(guān)Vue3 watch無法監(jiān)聽內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
vue如何修改data中的obj數(shù)據(jù)的屬性
這篇文章主要介紹了vue如何修改data中的obj數(shù)據(jù)的屬性,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-08-08Vue Router動態(tài)路由使用方法總結(jié)
這篇文章主要介紹了Vue Router動態(tài)路由使用方法總結(jié),需要的朋友可以參考下2023-10-10vue.js提交按鈕時(shí)進(jìn)行簡單的if判斷表達(dá)式詳解
這篇文章主要給大家介紹了關(guān)于vue.js提交按鈕時(shí)如何進(jìn)行簡單的if判斷表達(dá)式的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-08-08詳解vue中在循環(huán)中使用@mouseenter 和 @mouseleave事件閃爍問題解決方法
這篇文章主要介紹了詳解vue中在循環(huán)中使用@mouseenter 和 @mouseleave事件閃爍問題解決方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-04-04基于Vue3實(shí)現(xiàn)SSR(服務(wù)端渲染)功能
在現(xiàn)代網(wǎng)頁開發(fā)中,用戶體驗(yàn)日益成為網(wǎng)站成功的重要因素,從加載時(shí)間到SEO優(yōu)化,越來越多的開發(fā)者開始關(guān)注使用服務(wù)端渲染(SSR)來提升應(yīng)用的表現(xiàn),本文將深入探討 Vue 3 的 SSR 特性,并以示例代碼展示如何實(shí)現(xiàn)這一功能,需要的朋友可以參考下2024-11-11VueCli生產(chǎn)環(huán)境打包部署跨域失敗的解決
這篇文章主要介紹了VueCli生產(chǎn)環(huán)境打包部署跨域失敗的解決,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-11-11