使用 shallowRef() 來繞開深度響應(yīng)

Vue 的響應(yīng)性系統(tǒng)默認(rèn)是深度的。雖然這讓狀態(tài)管理變得更直觀,但在數(shù)據(jù)量巨大時(shí),深度響應(yīng)性也會導(dǎo)致不小的性能負(fù)擔(dān),因?yàn)槊總€(gè)屬性訪問都將觸發(fā)代理的依賴追蹤。好在這種性能負(fù)擔(dān)通常這只有在處理超大型數(shù)組或?qū)蛹壓苌畹膶ο髸r(shí),例如一次渲染需要訪問 100,000+ 個(gè)屬性時(shí),才會變得比較明顯。因此,它只會影響少數(shù)特定的場景。
Vue 確實(shí)也為此提供了一種解決方案,通過使用 shallowRef() 和 shallowReactive() 來繞開深度響應(yīng)。淺層式 API 創(chuàng)建的狀態(tài)只在其頂層是響應(yīng)式的,對所有深層的對象不會做任何處理。這使得對深層級屬性的訪問變得更快,但代價(jià)是,我們現(xiàn)在必須將所有深層級對象視為不可變的,并且只能通過替換整個(gè)根狀態(tài)來觸發(fā)更新:
const shallowArray = shallowRef([/* 巨大的列表,里面包含深層的對象 */])// 這不會觸發(fā)更新...shallowArray.value.push(newObject)// 這才會觸發(fā)更新shallowArray.value = [...shallowArray.value, newObject]// 這不會觸發(fā)更新...shallowArray.value[0].foo = 1// 這才會觸發(fā)更新shallowArray.value = [{...shallowArray.value[0],foo: 1},...shallowArray.value.slice(1)]
shallowRef shallowRef
shallowRef 和 ref() 不同,淺層 ref 的內(nèi)部值將會原樣存儲和暴露,并且不會被深層遞歸地轉(zhuǎn)為響應(yīng)式。只有對 .value 的訪問是響應(yīng)式的。
shallowRef() 常常用于對大型數(shù)據(jù)結(jié)構(gòu)的性能優(yōu)化或是與外部的狀態(tài)管理系統(tǒng)集成。
示例
const state = shallowRef({ count: 1 })// 不會觸發(fā)更改state.value.count = 2// 會觸發(fā)更改state.value = { count: 2 }
shallowRef 和 reactive() 不同,這里沒有深層級的轉(zhuǎn)換:一個(gè)淺層響應(yīng)式對象里只有根級別的屬性是響應(yīng)式的。屬性的值會被原樣存儲和暴露,這也意味著值為 ref 的屬性不會被自動解包了。
淺層數(shù)據(jù)結(jié)構(gòu)應(yīng)該只用于組件中的根級狀態(tài)。請避免將其嵌套在深層次的響應(yīng)式對象中,因?yàn)樗鼊?chuàng)建的樹具有不一致的響應(yīng)行為,這可能很難理解和調(diào)試。
const state = shallowReactive({foo: 1,nested: {bar: 2}})// 更改狀態(tài)自身的屬性是響應(yīng)式的state.foo++// ...但下層嵌套對象不會被轉(zhuǎn)為響應(yīng)式isReactive(state.nested) // false// 不是響應(yīng)式的state.nested.bar++
通過使用 shallowRef() 和 shallowReactive() 來繞開深度響應(yīng),改善頁面加載和更新性能。
