Vue3?Watch踩坑實(shí)戰(zhàn)之watch監(jiān)聽(tīng)無(wú)效
ref 與 reactive
ref函數(shù)和reactive函數(shù)都是用來(lái)定義響應(yīng)式數(shù)據(jù)
但是reactive更適合定義引用類(lèi)型、ref適合定義基本數(shù)據(jù)類(lèi)型(可接收基本數(shù)據(jù)類(lèi)型和對(duì)象)
reactive
1、 深層次響應(yīng)式,本質(zhì)是將傳入的數(shù)據(jù)包裝成一個(gè)Proxy對(duì)象
2、 參數(shù)必須是對(duì)象或者數(shù)組,如果要讓對(duì)象的某個(gè)元素實(shí)現(xiàn)響應(yīng)式時(shí),需要使用toRefs,這樣每個(gè)都需要采用value方式訪問(wèn)
ref
1、函數(shù)參數(shù)可以是基本數(shù)據(jù)類(lèi)型,也可以接受對(duì)象類(lèi)型
2、如果參數(shù)是對(duì)象類(lèi)型時(shí),其實(shí)底層的本質(zhì)還是reactive
3、ref響應(yīng)式原理是依賴(lài)于Object.defineProperty()的get()和set()的
watch
在自身組件監(jiān)聽(tīng) reactive 對(duì)象
let a = reactive({test: 123, bg: 456, hh: {hhh: 78}})
// 定時(shí)器 1
setTimeout(() => {
a.test = 456
}, 2000)
// 定時(shí)器 2
setTimeout(() => {
a.hh.hhh = 56
}, 4000)
// 定時(shí)器 3
setTimeout(() => {
a = {}
}, 6000)
//
watch(a, () => {
// 定時(shí)器1, 2 可以觸發(fā)監(jiān)聽(tīng), 不需要deep也可以
// 定時(shí)器3 不能觸發(fā)監(jiān)聽(tīng), 因?yàn)閷?duì)象的地址已經(jīng)發(fā)生改變了
console.log("change")
})
// 函數(shù)返回方式 采用deep可以監(jiān)聽(tīng), 不加deep不能監(jiān)聽(tīng)
watch(
() => a,
() => {
console.log(" func change")
},
{
deep: true
}
)為什么不加 deep不能監(jiān)聽(tīng)呢,直接從源碼看
function watch(source, cb, options) {
if (!isFunction(cb)) {
warn2(
`\`watch(fn, options?)\` signature has been moved to a separate API. Use \`watchEffect(fn, options?)\` instead. \`watch\` now only supports \`watch(source, cb, options?) signature.`
);
}
return doWatch(source, cb, options);
}
function doWatch(source, cb, { immediate, deep, flush, onTrack, onTrigger } = EMPTY_OBJ) {
// 代碼不完整,截取部分
...
if (isRef(source)) {
getter = () => source.value;
forceTrigger = isShallow(source);
} else if (isReactive(source)) {
// 這里 ,如果 source 是 reactive
// 則 deep = true
// 而 deep 為true 后面會(huì) 執(zhí)行traverse
getter = () => source;
deep = true;
} else if (isArray(source)) {
isMultiSource = true;
forceTrigger = source.some((s) => isReactive(s) || isShallow(s));
getter = () => source.map((s) => {
if (isRef(s)) {
return s.value;
} else if (isReactive(s)) {
return traverse(s);
} else if (isFunction(s)) {
return callWithErrorHandling(s, instance, 2 /* WATCH_GETTER */);
} else {
warnInvalidSource(s);
}
});
} else if (isFunction(source)) {
// 如果是函數(shù),
//最終 getter () => fn()
// deep為false,因此不走 traverse()
if (cb) {
getter = () => callWithErrorHandling(source, instance, 2 /* WATCH_GETTER */);
} else {
getter = () => {
if (instance && instance.isUnmounted) {
return;
}
if (cleanup) {
cleanup();
}
return callWithAsyncErrorHandling(
source,
instance,
3 /* WATCH_CALLBACK */,
[onCleanup]
);
};
}
} else {
getter = NOOP;
warnInvalidSource(source);
}
....
if (cb && deep) {
const baseGetter = getter;
getter = () => traverse(baseGetter());
}
}traverse 深度遍歷整個(gè)對(duì)象,深層次的訪問(wèn)其所有的響應(yīng)式變量,并收集依賴(lài)
在自身組件監(jiān)聽(tīng) ref 對(duì)象
let a = ref({test: 123, bg: 456, hh: {hhh: 78}})
setTimeout(() => {
a.value.test = 456
}, 2000)
setTimeout(() => {
a.value.hh.hhh = 56
}, 4000)
setTimeout(() => {
a.value = {}
}, 6000)
// 注意下面兩種寫(xiě)法 一個(gè)是 a , 一個(gè)是 a.value
// 從源碼可知, 如果是 a, 那么走isRef(source)分支, 如果是 a.value 那么走 isReactive(分支)
// 這里不給出結(jié)果,動(dòng)手試試
watch(a.value, (val) => {
console.log(val, "change")
})
watch(a, (val) => {
console.log(val, "change")
})
// 如果是 函數(shù)返回的方式呢? 其實(shí)也分兩種,類(lèi)推即可,同時(shí)也需要注意是否需要加 deep 屬性
watch(() => a.value, (val) => {
console.log(val, "change")
})
watch(() => a, (val) => {
console.log(val, "change")
})如果在子組件需要監(jiān)聽(tīng)父組件的數(shù)據(jù),同時(shí)父組件可以通過(guò)v-model雙向綁定時(shí)需要非常注意,不然可能出現(xiàn)一些bug
如果watch監(jiān)聽(tīng)無(wú)效,根據(jù)你的數(shù)據(jù)結(jié)構(gòu)分析是否是因?yàn)閷?xiě)法不正確導(dǎo)致。
總結(jié)
到此這篇關(guān)于Vue3 Watch踩坑實(shí)戰(zhàn)之watch監(jiān)聽(tīng)無(wú)效的文章就介紹到這了,更多相關(guān)Vue3 watch監(jiān)聽(tīng)無(wú)效內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- 一文詳解Vue3的watch是如何實(shí)現(xiàn)監(jiān)聽(tīng)的
- Vue3中watch監(jiān)聽(tīng)的五種情況詳解
- vue3中watch監(jiān)聽(tīng)的四種寫(xiě)法
- Vue3.0監(jiān)聽(tīng)器watch與watchEffect詳解
- Vue3中watch無(wú)法監(jiān)聽(tīng)的解決辦法
- 詳解Vue3中Watch監(jiān)聽(tīng)事件的使用
- vue3界面使用router及使用watch監(jiān)聽(tīng)router的改變
- Vue3中watch監(jiān)聽(tīng)使用詳解
- 詳解vue3中watch監(jiān)聽(tīng)的幾種情況
相關(guān)文章
分分鐘學(xué)會(huì)vue中vuex的應(yīng)用(入門(mén)教程)
本篇文章主要介紹了vue中vuex的應(yīng)用(入門(mén)教程),詳細(xì)的介紹了vuex.js和應(yīng)用方法,有興趣的可以了解一下2017-09-09
vue結(jié)合leaflet實(shí)現(xiàn)地圖放大鏡
放大鏡在很多地方都可以使用的到,本文主要介紹了vue結(jié)合leaflet實(shí)現(xiàn)地圖放大鏡,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-06-06
淺談Vue.js應(yīng)用的四種AJAX請(qǐng)求數(shù)據(jù)模式
本篇文章主要介紹了淺談Vue.js應(yīng)用的四種AJAX請(qǐng)求數(shù)據(jù)模式,本文將詳細(xì)介紹在Vue應(yīng)用程序中實(shí)現(xiàn)AJAX的四個(gè)方法,有興趣的可以了解一下2017-08-08

