Photo by patrick le on Unsplash
資源
- 共通
- vue2
- Vue官網 2.x -Reactivity in Depth
- [掘竅] 為什麼畫面沒有隨資料更新 - Vue 響應式原理(Reactivity)
- [MDN] Object.defineProperty
- vue2 響應式原始碼
- vue3
主題
Vue2
vue初始化頁面時:
Object.defineProperty
重新設定data
內的值(轉換成 getter / setter),- 蒐集
watcher
(第一次get的時候紀錄watcher) set
變動資料時,通知該對象底下所有watcher
觸發頁面重新渲染
注: 每個component都有各自的watcher
注: 因 Object.defineProperty,所以 vue2 不支持IE8以下
造成的問題
無法偵測到特定型態(Object, Array)的某些變動
- Object 新增刪除屬性
// 官網範例
var vm = new Vue({
data: {
a: 1
}
})
// `vm.a` is now reactive
vm.b = 2
// `vm.b` is NOT reactive
解法為使用 $set
Vue.set(vm.someObject, 'b', 2)
或者 this.$set(this.someObject, 'b', 2)
- Array 內容或長度值的'直接'修改
var vm = new Vue({
data: {
items: ['a', 'b', 'c']
}
})
vm.items[1] = 'x' // is NOT reactive
vm.items.length = 2 // is NOT reactive
解法為使用 $set 或者使用 Array.splice
這些Array方法可以被觀測到: push(), pop(), shift(), unshift(), splice(), sort(), reverse()
Vue3
Vue3 使用 ES6 proxy
代替 Object.defineProperty,proxy 可以直接代理 set行為,而且可以直接監聽到特定型態(Object, Array)的變動
- reactive() 建立響應式資料(使用 proxy)
- 頁面渲染過程中觸發getter, 蒐集依賴(track)
- 當資料變動 set時,觸發 tigger 找到關聯callback,更新頁面
Vue3響應式的流程圖
出自:(頁首資源7)你可以手寫Vue3的響應式原理嗎?
Proxy / Object.defineProperty 比較
- Proxy 解決vue2原本特定狀況無法監聽到的問題
- Proxy 相較於 Object.defineProperty 有更多新方法可以使用
- Proxy 可以直接操作代理的物件,而 Object.defineProperty 需要歷遍整個物件修改
- Proxy 即將成為新標準,效能會相對好些
總結
看看底層實作才了解到,原來以前vue2踩的渲染坑,是這樣出現的