最新,Vue 改進了響應式 API 中 Getter 的用法!
近日,Vue 改進了響應式 API 中 getter 的用法,主要包括:
- 一個用于將不同來源(value / ref / getter)規范化為值的 API(通過引入 toValue())
- 一個用于將不同來源(value / ref / getter)規范化為引用的 API(通過增強 toRef())
- 引入 MaybeRef<T> 和 MaybeRefOrGetter<T> 類型
通常需要將狀態傳遞到組合式函數中并保持響應性。在大多數情況下,這意味著要將響應源轉換為 ref:
目前,toRef 僅用于從對象中“提取”單個屬性。這就有點不靈活,例如,如果想將嵌套屬性轉換為 ref:
上面的代碼有兩個問題:
- 調用 toRef 時 props.foo 可能不存在
- 如果 props.foo 被交換到不同的對象,這將無法處理這種情況。
為了解決這個問題,可以使用 computed:
但是,在這里使用 computed? 并不是最佳選擇。在內部,computed? 創建一個單獨的 effect? 來緩存計算值。當 getter 只訪問屬性而不執行任何昂貴的計算時,這實際上是很大的開銷。
將非引用響應狀態傳遞到組合式函數的成本最低的方法就是用 getter? 包裝它(或“thunking”——即延遲實際值的訪問,直到調用 getter):
VueUse 已經廣泛支持這種模式,這也有點類似于在 Solid 中看到的函數式 signals(信號)。
此外,這種模式在使用響應式 props 解構時會很常用:
引入 toValue()
在組合式函數中,其參數可以接受值或引用。這可以表示為:
為了也支持 getters,接受的類型將是:
目前提供的unref?將 MaybeRef<T>? 規范化為 T?。但是,不能讓 unref? 也解包 getter?,因為這將是一個破壞性的變化。可以在函數值上調用 unref 并期望返回該函數。這種情況比較少見,但仍然是無法破解的可能情況。
因此,引入一個新方法,toValue():
這就相當于 VueUse 的 [resolveUnref()](https://vueuse.org/shared/resolveUnref/)?。這里將其命名為 toValue()? 是因為它與 toRef() 相反:兩者代表兩個不同的規范化方向:
增強 toRef()
當然也可能存在需要 ref? 的情況——不能傳遞 getter?。對于這種情況,仍然可以使用 computed?。但如前所述,computed? 對于只訪問屬性的簡單 getter 來說是一種矯枉過正。
可以向 toRef()? 添加新的重載,以便它現在可以接受 getters :
以這種方式創建的 ref? 是只讀的,只是在每次訪問 .value? 時調用 getter。
toRef() 現在應該被視為“將 value / ref / getter 規范化為 refs” 的 API:
這就相當于 VueUse 的 [resolveRef()](https://vueuse.org/shared/resolveRef/)。
現在仍然支持舊的 toRef(object, 'key')? 用法,但應該首選更靈活的 getter 語法:
向后移植到 v2.7?
將這些功能添加在 v3.3 和 v2.7 之間造成了差異——雖然理論上不再回向 v2.7 添加新的功能,但這些可能值得向后移植以確保 vue-demi? 和依賴于 vue-demi 的 VueUse 的行為一致性。
如果向后移植到 2.7,VueUse 也可以用 toRef? 和 toValue? 來替換 resolveRef? 和 resolveUnref。
參考:https://github.com/vuejs/core/pull/7997