vue3使用watch監(jiān)聽props的值的注意事項(xiàng)及說明
在 Vue 的響應(yīng)式系統(tǒng)中,直接監(jiān)聽 props.optionData 并啟用 deep: true 仍失效的原因,主要與 響應(yīng)式代理的復(fù)用機(jī)制 和 深度監(jiān)聽的實(shí)現(xiàn)邏輯 有關(guān)。
以下是具體分析:
一、核心原因:響應(yīng)式代理的復(fù)用
父組件傳遞新對象的代理處理
父組件通過 computed 生成的 optionData 每次都是新對象,但 Vue 在子組件中接收 props.optionData 時會自動將其轉(zhuǎn)換為 響應(yīng)式代理對象(Proxy)。
若父組件傳遞的新對象與原代理對象的 結(jié)構(gòu)相同,Vue 可能會 復(fù)用已有的代理實(shí)例,導(dǎo)致引用地址未發(fā)生明顯變化。
此時,直接監(jiān)聽 props.optionData 實(shí)際監(jiān)聽的是代理對象的引用地址,而非父組件原始對象的地址。
deep: true的局限性deep: true的作用是遞歸監(jiān)聽對象 所有層級的屬性變化,但前提是 代理對象本身的引用地址已被正確追蹤 。
若代理對象的引用地址未變(被復(fù)用),即使內(nèi)部屬性發(fā)生變化,Vue 也會認(rèn)為 props.optionData 未發(fā)生“頂層”變化,從而跳過深度遍歷。
二、實(shí)驗(yàn)驗(yàn)證與現(xiàn)象解釋
- 父組件代碼示例
// 父組件每次生成新對象
const optionData = computed(() => ({
title: 'Weekly Sales',
xAxis: { data: categories.value },
series: [{ data: values.value }]
}));- 子組件監(jiān)聽邏輯
// 直接監(jiān)聽 props.optionData(失效)
watch(
props.optionData,
(newVal) => {
console.log('觸發(fā)監(jiān)聽');
},
{ deep: true } // 仍不觸發(fā)
);- 現(xiàn)象解釋
引用地址未變:Vue 復(fù)用代理對象,導(dǎo)致 props.optionData 的引用地址在子組件中未變化,因此 watch 認(rèn)為未發(fā)生“頂層”變化,跳過深度檢查。
依賴收集失?。?code>deep: true 需要訪問對象的所有屬性以建立依賴關(guān)系,但若代理對象未觸發(fā)屬性訪問(如未實(shí)際使用嵌套屬性),依賴鏈可能不完整。
三、解決方案
- 改用函數(shù)形式監(jiān)聽
通過 函數(shù)返回 props.optionData,強(qiáng)制 Vue 在每次依賴收集時重新獲取原始值,繞過代理復(fù)用機(jī)制:
watch(
() => props.optionData, // 動態(tài)獲取最新值
(newVal) => {
console.log('觸發(fā)監(jiān)聽');
},
{ deep: true }
);- 強(qiáng)制生成唯一標(biāo)識
在父組件中為對象添加 唯一鍵(如時間戳),確保每次生成的新對象結(jié)構(gòu)不同,避免代理復(fù)用:
const optionData = computed(() => ({
...config,
_key: Date.now() // 破壞結(jié)構(gòu)一致性
}));- 顯式觸發(fā)引用變化
在子組件中手動比較新舊值的 序列化結(jié)果,強(qiáng)制觸發(fā)更新:
watch(
() => JSON.stringify(props.optionData),
(newVal, oldVal) => {
if (newVal !== oldVal) {
console.log('觸發(fā)監(jiān)聽');
}
}
);總結(jié)
| 場景 | 直接監(jiān)聽 props.optionData | 函數(shù)形式 () => props.optionData |
|---|---|---|
| 代理復(fù)用 | 可能復(fù)用代理,引用地址未變 | 動態(tài)獲取最新值,繞過代理復(fù)用 |
| deep: true 生效條件 | 依賴代理地址變化 | 直接追蹤原始對象變化 |
| 性能開銷 | 低(淺層監(jiān)聽) | 高(深度遞歸 + 動態(tài)依賴收集) |
推薦方案:
- 優(yōu)先使用函數(shù)形式監(jiān)聽,并結(jié)合
deep: true確保深度屬性變化的檢測。 - 若性能敏感,可通過唯一標(biāo)識或序列化優(yōu)化依賴鏈。
以上為個人經(jīng)驗(yàn),希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
Vue?+?ElementUI表格內(nèi)實(shí)現(xiàn)圖片點(diǎn)擊放大效果的兩種實(shí)現(xiàn)方式
這篇文章主要介紹了Vue?+?ElementUI表格內(nèi)實(shí)現(xiàn)圖片點(diǎn)擊放大效果的兩種實(shí)現(xiàn)方式,第一種使用el-popover彈出框來實(shí)現(xiàn)而第二種使用v-viewer插件實(shí)現(xiàn),需要的朋友可以參考下2024-08-08
vue中的vue-print-nb如何實(shí)現(xiàn)頁面打印
這篇文章主要介紹了vue中的vue-print-nb如何實(shí)現(xiàn)頁面打印,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-04-04
Vuex狀態(tài)機(jī)的快速了解與實(shí)例應(yīng)用
Vuex是專門為Vuejs應(yīng)用程序設(shè)計(jì)的狀態(tài)管理工具,這篇文章主要給大家介紹了關(guān)于Vuex狀態(tài)機(jī)快速了解與實(shí)例應(yīng)用的相關(guān)資料,需要的朋友可以參考下2021-06-06
Vue render渲染時間戳轉(zhuǎn)時間,時間轉(zhuǎn)時間戳及渲染進(jìn)度條效果
這篇文章主要介紹了Vue render渲染時間戳轉(zhuǎn)時間,時間轉(zhuǎn)時間戳及渲染進(jìn)度條效果,通過實(shí)例代碼相結(jié)合的形式給大家介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下2018-07-07
Vue.js實(shí)現(xiàn)簡單計(jì)時器應(yīng)用
這篇文章主要為大家詳細(xì)介紹了Vue.js實(shí)現(xiàn)簡單計(jì)時器應(yīng)用,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-09-09
Vue +WebSocket + WaveSurferJS 實(shí)現(xiàn)H5聊天對話交互的實(shí)例
這篇文章主要介紹了Vue +WebSocket + WaveSurferJS 實(shí)現(xiàn)H5聊天對話交互的實(shí)例,幫助大家更好的理解和學(xué)習(xí)vue,感興趣的朋友可以了解下2020-11-11

