昨天我們提到,Vue 3.6 在底層 runtime 針對「多個 composable 的組合」做了效能優化:
透過 EffectScope 與依賴追蹤的改進,現在 Vue 可以更精準地管理多層 composable 的副作用與清理,讓「組合越多」反而不會拖慢效能。
但框架跑得快只是基礎,如果我們自己寫的 composable 沒有遵守良好規範,再強的 runtime 也救不了糟糕的組合。
接下來,我們就從開發者的角度出發,看看要如何撰寫「真正可重用、能與 Vue 3.6 優化互生共利」composable。
Vue 3.6 透過 EffectScope 將副作用包在更小的作用域中,只有在 composable 的依賴改變時才會重新計算。
composable 輸入要明確、輸出要乾淨,Vue 才能正確建立依賴樹,減少不必要的追蹤。
export function useCounter(initial = 0) {
const count = ref(initial)
const inc = () => count.value++
const dec = () => count.value--
return { count, inc, dec }
}
不要在內部偷偷操作 DOM 或綁死外部狀態,否則 Vue 的依賴追蹤無法最佳化。
export function useCounterWithDom() {
const count = ref(0)
const inc = () => {
count.value++
document.querySelector('#counter').textContent = count.value // 不良示範 :;(∩´﹏`∩);:
}
return { count, inc }
}
Composable 的 ref
或 reactive
應該獨立可運作,不要依賴不可控的全域狀態。
Vue 3.6 的 EffectScope 可以在 scope 銷毀時自動清理,但前提是你的狀態必須被 scope 正確包裹。
若一定要依賴外部,最好透過 參數或注入(
provide
/inject
、Pinia
)來管理。
[useCounter]
├─ count (ref)
├─ inc()
└─ dec()
onScopeDispose
是加速關鍵Vue 3.6 的優化核心之一,是更快的副作用回收機制。
如果副作用寫在 Composable 內,記得使用 onScopeDispose
,這樣當外層 scope 結束時,Vue 能即時清理監聽器與計時器,避免不必要的重計算與記憶體浪費。
export function useMouse() {
const x = ref(0), y = ref(0)
const update = (e: MouseEvent) => {
x.value = e.pageX
y.value = e.pageY
}
window.addEventListener('mousemove', update)
onScopeDispose(() => {
window.removeEventListener('mousemove', update)
})
return { x, y }
}
Vue 3.6 的依賴追蹤在多個 composable 混合時會更高效,但前提是每個 composable 彼此獨立,不要寫死對特定 UI 或 API 的依賴。
Composable: return { data, loading }
UI Layer: <DataTable :value="data" v-if="!loading" />
Vue 官方建議:以 useXxx 命名,可立即辨識為 composable,一眼看出來是「邏輯函式」而非「普通工具函式」。
抽象層次適中:太細會增加 Vue 追蹤成本,太粗會降低組合彈性,把握抽離跨元件可共用的原則,UI 還是交給元件自己處理。
在 Vue 3.6 中,合理拆分可以讓 EffectScope 發揮最大效能。
Vue 3.6 已經在 runtime 幫我們打好了「組合加速器」的地基,但要真正享受「多個 composable 一起跑得更快」的紅利,我們必須寫出乾淨、獨立、可被 EffectScope 精準管理的 composable。
框架 + 寫法 = 真正的效能優化,這就是 Vue 3.6 帶來的新時代:
不是只有底層快,開發者的組合思維也要跟著升級。