Vue3中shallowRef和shallowReactive的性能優(yōu)化
大家對(duì) Vue3 的 ref 和 reactive 都很熟悉,那么對(duì) shallowRef 和 shallowReactive 是否了解呢?
在編程和數(shù)據(jù)結(jié)構(gòu)中,“shallow”(淺層)通常指對(duì)數(shù)據(jù)結(jié)構(gòu)的最外層進(jìn)行操作,而不遞歸地處理其內(nèi)部或嵌套的數(shù)據(jù)。這種處理方式關(guān)注的是數(shù)據(jù)結(jié)構(gòu)的第一層屬性或元素,而忽略更深層次的嵌套內(nèi)容。
1. 淺層與深層的對(duì)比
1.1 淺層(Shallow)
定義:只對(duì)數(shù)據(jù)結(jié)構(gòu)的最外層進(jìn)行操作或跟蹤。對(duì)于嵌套的屬性或?qū)ο?,不?huì)遞歸地追蹤其內(nèi)部的變化。
應(yīng)用:在需要優(yōu)化性能時(shí),減少不必要的深層次數(shù)據(jù)追蹤。比如:shallowRef 和 shallowReactive 提供了這種功能。
優(yōu)點(diǎn):提高性能,減少 Vue 內(nèi)部的深度響應(yīng)式追蹤,特別是在數(shù)據(jù)結(jié)構(gòu)復(fù)雜時(shí)效果顯著。
缺點(diǎn):無法自動(dòng)跟蹤嵌套對(duì)象或數(shù)組內(nèi)部的變化,需要手動(dòng)處理或選擇其他方式。
1.2 深層(Deep)
定義:對(duì)數(shù)據(jù)結(jié)構(gòu)的所有層級(jí)都進(jìn)行操作或跟蹤。遞歸地追蹤嵌套的對(duì)象或數(shù)組中的所有屬性。
應(yīng)用:在需要全面跟蹤數(shù)據(jù)變化時(shí),例如使用 reactive 進(jìn)行深層響應(yīng)式追蹤。
優(yōu)點(diǎn):能夠自動(dòng)跟蹤嵌套的所有屬性變化,確保數(shù)據(jù)的每一層都響應(yīng)式。
缺點(diǎn):性能開銷較大,特別是在數(shù)據(jù)結(jié)構(gòu)非常復(fù)雜或龐大時(shí)。
下面簡(jiǎn)單介紹一下它們吧。
shallowRef 和 shallowReactive 是 Vue3 提供的 API,它們與 ref 和 reactive 類似,不同點(diǎn)在于它們只會(huì)淺層地監(jiān)聽對(duì)象或數(shù)組的變化。也就是說,它們不會(huì)遞歸監(jiān)聽對(duì)象或數(shù)組的深層次屬性,只會(huì)監(jiān)聽第一層屬性的變化。
2. shallowRef
2.1 用途
shallowRef 用于創(chuàng)建一個(gè)淺層響應(yīng)式的引用。與 ref 不同,shallowRef 只會(huì)追蹤引用值的第一層數(shù)據(jù)變化,而不會(huì)遞歸追蹤嵌套對(duì)象的變化。
2.2 使用場(chǎng)景
當(dāng)有一個(gè)復(fù)雜的數(shù)據(jù)結(jié)構(gòu),但只關(guān)心數(shù)據(jù)結(jié)構(gòu)的頂層變化時(shí),可以使用 shallowRef。這種方式可以避免不必要的深層次響應(yīng)式追蹤,提高性能。
舉個(gè) ??
<template> <div>{{ obj }}</div> </template> <script> import { shallowRef, watchEffect } from 'vue'; export default { setup() { const obj = shallowRef({ nested: { a: 1, b: 2, }, }); obj.value = { nested: { a: 10, b: 20 } }; obj.value.nested.a = 100; watchEffect(() => { console.log('obj change:', obj.value.nested); }); return { obj, }; }, }; </script>
按照我們對(duì) shallowRef 的理解,修改 nested 對(duì)象的 a 屬性不會(huì)觸發(fā)響應(yīng)式更新,因?yàn)?shallowRef 只追蹤 obj.value 的第一層。只有當(dāng)整個(gè) obj.value 被重新賦值時(shí),Vue 才會(huì)進(jìn)行視圖更新。
- obj.value = { nested: { a: 10, b: 20 } }; 重新賦值整個(gè)對(duì)象時(shí),觸發(fā)更新;
- obj.value.nested.a = 100; 不會(huì)觸發(fā)視圖更新,因?yàn)檫@是嵌套對(duì)象的屬性。
但實(shí)際如下:兩次對(duì) obj 的修改均起作用,這是怎么回事呢?
2.3 解釋原因
注意注意??:shallowRef 對(duì)嵌套對(duì)象的屬性變化仍會(huì)觸發(fā)視圖更新。
shallowRef 創(chuàng)建的對(duì)象對(duì)于頂層屬性和嵌套屬性的變化都有響應(yīng)式處理,只不過對(duì)于嵌套屬性的響應(yīng)式處理是依賴于頂層對(duì)象的變化。
- 頂層屬性:shallowRef 只會(huì)追蹤頂層引用的變化。這意味著我們可以用 shallowRef 來存儲(chǔ)一個(gè)對(duì)象或數(shù)組,修改這個(gè)對(duì)象或數(shù)組的引用會(huì)觸發(fā)視圖更新。
- 嵌套屬性:對(duì)于嵌套屬性的修改,實(shí)際上 shallowRef 也會(huì)觸發(fā)更新,因?yàn)?Vue 的響應(yīng)式系統(tǒng)會(huì)處理嵌套對(duì)象的變化。
這是因?yàn)?Vue 的響應(yīng)式系統(tǒng)會(huì)代理整個(gè)對(duì)象,包括嵌套對(duì)象。即使 shallowRef 只對(duì)頂層進(jìn)行淺層響應(yīng),嵌套對(duì)象的屬性依然會(huì)被處理,以確保更新的正確性。
因此:
- obj.value = { nested: { a: 10, b: 2 } }; 修改頂層屬性,會(huì)觸發(fā)視圖更新;
- obj.value.nested.a = 100; 修改嵌套屬性,也會(huì)觸發(fā)視圖更新。
對(duì)于這一點(diǎn),大家在使用時(shí)需要特別注意!
3. shallowReactive
3.1 用途
shallowReactive 用于創(chuàng)建一個(gè)淺層響應(yīng)式對(duì)象。與 reactive 類似,shallowReactive 只會(huì)追蹤對(duì)象或數(shù)組的第一層屬性變化,而不會(huì)追蹤深層嵌套屬性的變化。
3.2 使用場(chǎng)景
適用于復(fù)雜對(duì)象或數(shù)組,但只關(guān)心對(duì)象的第一層屬性變化的場(chǎng)景。通過使用 shallowReactive 可以提高性能,減少 Vue 遞歸追蹤數(shù)據(jù)的開銷。
舉個(gè) ??
<template> <div>{{ obj }}</div> </template> <script> import { shallowRef, watchEffect, shallowReactive } from 'vue'; export default { setup() { const obj = shallowReactive({ firstLayer: { nested: { a: 1, b: 2 }, }, }); obj.firstLayer = { nested: { a: 10, b: 20 } }; obj.firstLayer.nested.a = 20; watchEffect(() => { console.log('watchEffect obj.firstLayer: ', obj.firstLayer); }); return { obj, }; }, }; </script>
結(jié)果顯然:
在 shallowReactive 中,雖然 Vue 文檔中提到 shallowReactive 只會(huì)追蹤頂層屬性的響應(yīng)式更新,但實(shí)際上它的行為與 shallowRef 類似。即使使用 shallowReactive,嵌套對(duì)象的某些修改也可能觸發(fā)響應(yīng)式更新。這是因?yàn)?Vue 內(nèi)部的響應(yīng)式系統(tǒng)并沒有完全忽略嵌套屬性,尤其是在某些情況下,Vue 會(huì)使用 Proxy 機(jī)制對(duì)嵌套對(duì)象進(jìn)行代理,因此仍然可能觸發(fā)視圖更新。
4. 為什么會(huì)觸發(fā)響應(yīng)式更新?
1、Proxy 代理機(jī)制
Vue 的響應(yīng)式系統(tǒng)通過 Proxy 來代理對(duì)象,即使使用 shallowRef 和 shallowReactive 也意味著 Vue 可能會(huì)為某些嵌套屬性創(chuàng)建代理。這使得嵌套屬性的修改在某些場(chǎng)景下依然會(huì)被追蹤。
2、淺層追蹤但部分嵌套依然可見
雖然 shallowRef 和 shallowReactive 主要用于優(yōu)化性能,避免深度嵌套數(shù)據(jù)的自動(dòng)響應(yīng)式追蹤,但對(duì)于淺層的屬性,Vue 仍然會(huì)在某些情況下處理這些嵌套的數(shù)據(jù)結(jié)構(gòu)。
對(duì)于 更深層次 的理解:
二者的初衷是減少 Vue 內(nèi)部對(duì)深度嵌套對(duì)象的遞歸代理操作,但并不代表 Vue 會(huì)完全忽略嵌套屬性的變化。這種“半淺層”的響應(yīng)式處理方式使它能夠有效追蹤淺層屬性,同時(shí)在某些情況下允許嵌套屬性的修改被捕獲。
注意??:
雖然 shallowRef 和 shallowReactive 的某些嵌套屬性會(huì)被代理并追蹤其變化,進(jìn)而導(dǎo)致修改這些屬性時(shí)觸發(fā)視圖更新,但如果項(xiàng)目中深層嵌套的數(shù)據(jù)非常復(fù)雜且變化頻繁,二者依然可以減少 Vue 的深層追蹤,優(yōu)化性能。
5. 對(duì)比
5.1 shallowRef 和 shallowReactive
1、數(shù)據(jù)類型的適用性
- shallowRef:適用于簡(jiǎn)單類型、引用類型(如對(duì)象、數(shù)組等),它包裝了一個(gè)引用數(shù)據(jù)。
- shallowReactive:適用于對(duì)象類型,它將整個(gè)對(duì)象的第一層做響應(yīng)式處理。
2、深層次數(shù)據(jù)的處理
shallowRef 和 shallowReactive 都不會(huì)遞歸偵聽深層次數(shù)據(jù),但 Vue 本身在修改深層屬性時(shí)觸發(fā)更新。若需要監(jiān)聽深層次的數(shù)據(jù)變更,應(yīng)該使用 ref 或 reactive,它們會(huì)遞歸地監(jiān)聽所有層級(jí)的屬性。
3、性能優(yōu)勢(shì)
對(duì)于只需要監(jiān)聽頂層屬性變化的場(chǎng)景,shallowRef 和 shallowReactive 可以減少 Vue 內(nèi)部的追蹤操作,從而提升性能,特別是當(dāng)數(shù)據(jù)結(jié)構(gòu)非常復(fù)雜或龐大時(shí)。
5.2 ref 和 reactive
ref
- 深層響應(yīng):對(duì)所有層級(jí)的屬性進(jìn)行響應(yīng)式處理,包括嵌套對(duì)象或數(shù)組。
- 行為:修改引用值以及嵌套對(duì)象的任意屬性,都會(huì)觸發(fā)響應(yīng)式更新。
- 適用場(chǎng)景:適用于需要對(duì)復(fù)雜數(shù)據(jù)結(jié)構(gòu)進(jìn)行全方位追蹤,確保所有層級(jí)變化都被檢測(cè)到的場(chǎng)景。
reactive
- 深層響應(yīng):對(duì)整個(gè)對(duì)象及其嵌套屬性進(jìn)行遞歸式的響應(yīng)式代理。
- 行為:無論頂層屬性還是嵌套屬性的修改,都會(huì)觸發(fā)視圖更新。
- 適用場(chǎng)景:適合需要對(duì)深度嵌套對(duì)象進(jìn)行全面追蹤的場(chǎng)景,通常用于大部分 Vue 項(xiàng)目中。
5.3 注意事項(xiàng)
1、設(shè)計(jì)意圖
Vue 3 提供 shallowRef 和 shallowReactive 是為了在不需要深度追蹤數(shù)據(jù)的場(chǎng)景下優(yōu)化性能。應(yīng)根據(jù)具體的業(yè)務(wù)需求選擇合適的響應(yīng)式方式。
2、響應(yīng)性丟失的風(fēng)險(xiǎn)
如果使用了 shallowRef 和 shallowReactive,嵌套對(duì)象的屬性在直接修改時(shí)不會(huì)觸發(fā)響應(yīng)式更新,這可能導(dǎo)致一些視圖更新的邏輯失效,使用時(shí)需要明確知道這一點(diǎn)。
最后,在使用時(shí)要根據(jù)具體需求進(jìn)行權(quán)衡,合理選擇使用 ref、reactive 或淺層響應(yīng)式 API。
到此這篇關(guān)于Vue3中shallowRef和shallowReactive的性能優(yōu)化的文章就介紹到這了,更多相關(guān)Vue3 shallowRef和shallowReactive內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
vue中使用animate.css實(shí)現(xiàn)炫酷動(dòng)畫效果
這篇文章主要介紹了vue中使用animate.css實(shí)現(xiàn)動(dòng)畫效果,我們使用它,只需要寫很少的代碼,就可以實(shí)現(xiàn)非常炫酷的動(dòng)畫效果,感興趣的朋友跟隨小編一起看看吧2022-04-04vue.js引用背景圖background無效的3種解決方案
這篇文章主要介紹了vue.js引用背景圖background無效的3種解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-08-08關(guān)于ELement?UI時(shí)間控件el-date-picker誤差8小時(shí)的問題
本文探討了在使用Vue前端框架配合ElementUI開發(fā)時(shí),遇到日期時(shí)間選擇器DateTimePicker的時(shí)間同步問題,通過揭示中國(guó)東八區(qū)與格林威治時(shí)間的時(shí)差,作者提供了設(shè)置value-format屬性的解決方案,以確保后端接收到的正確時(shí)間格式2024-08-08從零開始在NPM上發(fā)布一個(gè)Vue組件的方法步驟
這篇文章主要介紹了從零開始在NPM上發(fā)布一個(gè)Vue組件的方法步驟,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-12-12