
前言
就現代前端框架而言,身受我喜愛的 magic 之一,莫過於資料與畫面之間響應式 (Reactivity) 的連動,但用歸用,對於該技術背後原理的認知也是非常重要,不然它終究只是個 magic。
這篇主要會來瞭解 Vue3 ref 與 reactive 創建的方式差異為何。但在進入正文之前如果對於 Proxy 運作不太熟悉,可以參考以下文章!
Description
ref
ref 可接受任何型別的值,如傳入的型別為物件,會轉為 reactive 方法繼續實現。所以實際上 ref 主要負責將型別為物件以外的資料包裝起來變成具有響應效果。
接著由於我們已經針對自己需要的值創建出 ref 的物件,可透過 .value
存取該值,並且其背後就是利用 set, get 方法直接劫持我們對該值的訪問而不用額外使用 Proxy 來監聽。
讓我們看一下原始碼:
第 7 行:可以看到當在創建一個 ref 時, createRef
接收兩個參數,一個是型別為 unknown
的 rawValue
,另一個則是 shallow = false
藉以判斷是否為淺觀察。
第 9行:判斷傳入的 rawValue
是否已經為 ref,如果為 true 則直接返回當前值。
第 15 行:接著再判斷是否為淺觀察,如果為 true 就將當前傳入的參數指向 value
,反之為 false 則呼叫 convert()
並將 rawValue
傳入。
第 44 行:程式會依照剛剛所傳入的 rawValue
判斷是否為物件,如果為 true 呼叫 reactive()
。
第 18 行:對該傳入的值建立 ref 的結構,裡面提供 get, set 方法賦予該值有響應效果。
我們可以在上面的 get()
、 set()
裡面找到對應的 track()
以及 trigger()
,這部分是屬於 effect 的範疇,文章最後我們會來說明,這邊我們只要先記住 ref 的程式流程即可。
附上 ref 使用方式及回傳的結果:

reactive
reactive 對於傳入的參數只接受物件型別,如果傳入非物件型別的參數則會得到 value cannot be made reactivity
的通知。
下面依舊附上原始碼:
第 3 行:如果 target
有值且 target[ReactiveFlags.IS_READONLY] = true
的話就直接返回當前物件。
第 6 行:如果上述條件都不符合則呼叫 createReactiveObject()
並帶入以下四個參數:
target: 當前傳入的物件isReadOnly: 是否唯讀mutableHandlers:baseHandlers 的分支,針對可變的普通物件的行為做代理mutableCollectionHandlers:collectionHandlers 的分支,針對可變的集合物件做代理(Map、Set、WeakMap、WeakSet)
第 20 行:判斷 target
是否為物件
第 28 行:判斷 target
是否為 Reactive Object
第 35~39 行: 根據 isReadOnly
判斷 proxyMap
會等於哪個 WeakMap
,並透過 WeakMap.get() 判斷如果該 target
的 Proxy value 存在就返回該 target
第 41~44 行:判斷 target
的 type,返回的值有 COMMON, COLLECTION, INVALID
,如果得出 INVALID
則直接返回該 target
第 45~50 行:經過以上層層判斷,我們可替該 target
創建 Proxy 代理,並在第 49 行透過 WeakMap.set() 存放該 target
以及其相對應的 proxy
附上 reactive 使用方式及回傳的結果:

結論
每次讀原始碼時總會有很多的延伸閱讀,但侷限於主題的範圍,只能先就當前單元做解說,等完善後我會再列清單連結將相關主題擺放在一起,方便查詢。
回到本文結論~~
儘管在 ref 帶入物件參數它還是會自動轉到 reactive,但 ref 本質上並不是要處理物件型別的資料,所以為了明確區分其功能,個人習慣還是會分開使用。當然如果有更好的做法歡迎留言~~ 因為每個人的 coding 理念都不一樣說不定會激盪出更好的寫法。
對 Reactivity 有興趣的人也可以參考官方的文件,你會發現 reactive, ref 只是冰山一角,後續我也會補上對應的文章做分享!!!
Reference
https://vue3js.cn/vue-composition-api/#reactive