Vue 3 響應式原理四 - Computed Values & Vue 3 源碼

你可能會想說“為什么我們不直接使用計算屬性來處理這些副作用?”
這是我們的例子:

let product = reactive({ price: 5, quantity: 2 })
let salePrice = ref(0)
let total = 0
effect(() => {
  salePrice.value = product.price * 0.9
})
effect(() => {
  total = salePrice.value * product.quantity
})

我們來轉換一下:

let product = reactive({ price: 5, quantity: 2 })
let salePrice = computed(() => {
  return product.price * 0.9
})
let total = computed(() => {
  return salePrice.value * product.quantity
})

請注意salePrice計算屬性如何包含在total計算屬性中,我們需要使用.value訪問它。看起來我們正在創(chuàng)建另一個ref響應式引用。
下面是如何定義我們的computed函數(shù)

function computed(getter) {
  let result = ref()  // 創(chuàng)建一個新的響應式引用
  effect(() => (result.value = getter())) // 將 result 的值設置為 getter 的返回值
  return result // 返回這個 ref
}

這就是全部了。你可以在 Github 上找到完整代碼 computed.js.

規(guī)避了 Vue 2 中更改檢測警告的漏洞

值得一提的是,我們可以用響應式對象做一些 Vue 2 無法做到的事情。比如我們可以像這樣添加新的響應式式屬性:

let product = reactive({ price: 5, quantity: 2 })
...
product.name = 'Shoes'
effect(() => {
  console.log(`Product name is now ${product.name}`)
})
product.name = 'Socks'

就如你期望的那樣,控制臺打印出:

Product name is now Shoes
Product name is now Socks

這在 Vue 2 中是不可能的,因為 Vue 2 的響應性是用 Object.definePropertygettersetter添加到單個對象屬性來實現(xiàn)的。現(xiàn)在有了 Proxy,我們可以毫無顧慮地添加新屬性,并且它們可以立即響應。

我們的代碼 VS Vue 3 源碼

您可能想知道,我們的代碼是否能大致與 Vue 3 源碼等效?
可以像下圖那樣操作:

  • git clone vue-next
  • yarn install
    -yarn build reactivity。
  • 將在packages/reactivity/dist/找到的reactivity.cjs.js引入到我們的示例文件頂部,代替我們自己寫的reactive、computed、effect方法。

vue-3-reactivity

var { reactive, computed, effect } = require('./reactivity.cjs')
// 后面的代碼都一樣,故省略

打印的結果依然是一樣:

Before updated quantity total (should be 9) = 9 salePrice (should be 4.5) = 4.5
After updated quantity total (should be 13.5) = 13.5 salePrice (should be 4.5) = 4.5
After updated price total (should be 27) = 27 salePrice (should be 9) = 9
Product name is now Shoes
Product name is now Socks

嗯,所以我們的響應式系統(tǒng)是不是和 Vue 的差不多了 ?但真實情況 Vue 的版本肯定要復雜得多。 讓我們來看看構成 Vue 3 的響應式系統(tǒng)的文件吧。

Vue 3 響應式源碼文件

我們在 Vue 3 源碼包/packages/reactivity/src/可以找到以下文件。它們是TypeScript (ts)文件,但你應該能夠讀懂它們(即使不熟悉TS)。

  • effect.ts - 定義了effect函數(shù)(用來封裝可能包含響應式引用和對象的代碼)。還包含了 get 屬性時調用的track和 set 屬性調用的trigger。
  • baseHandlers.ts - 包含 Proxy handlers,譬如getset, 它們分別調用了tracktrigger(來自effect.ts)。
  • reactive.ts - 定義了響應式語法的功能,它創(chuàng)建了一個 ES6 Proxy,并使用getset(來自basehandlers.ts)作為 proxy 的處理程序(handlers)。
  • ref.ts - 通過對象訪問器定義創(chuàng)建響應式引用的方法。還包含toRefs,它將響應式對象轉換為訪問原始 proxy 的一個個響應式引用。
  • computed.ts - 定義了計算屬性,使用effect和對象訪問器并且返回了一個類似Ref的對象。(和我們的實現(xiàn)稍微有點不同)。

這些文件包含了 Vue 響應式系統(tǒng)的核心功能。

Vue 3 響應式原理一 - Vue 3 Reactivity
Vue 3 響應式原理二 - Proxy and Reflect
Vue 3 響應式原理三 - activeEffect & ref
Vue 3 響應式原理四 - Computed Values & Vue 3 源碼

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容