[Vue 3] 為什么需要同時使用 Ref 和 Reactive
AICube 開放GPT-4給大家使用以及AI工具助手,可以簡化大家生圖的的prompt。
在使用 Options API 工作時聲明響應性數據是直截了當的。data 選項內的所有內容都會自動變為響應性,并在模板中可用。唯一需要注意的是,要將data設為一個函數,以防止在所有組件實例之間共享狀態。
讓我們討論一下Vue 3中發生了什么變化,以及為什么我們需要兩個不同的助手。
Vue 2中的響應性
data 組件選項內的每個屬性都將通過 Object.defineProperty 轉換為getter/setter。這些getter/setter對我們來說是看不見的,但在底層,它們使Vue在訪問或修改屬性時能夠執行依賴跟蹤。
每個組件都有一個關聯的觀察者,用于跟蹤在組件的渲染周期中使用的屬性。如果依賴項更新,觀察者會通知組件,然后觸發重新渲染。
Vue 3中的響應性
在 Vue 3 中,一切都發生了變化。核心部分從零開始重寫,現在由Javascript Proxies提供響應性。Proxies是一種現代且優雅的方式來觀察一個對象并在其屬性被訪問或更新時得到通知。
可以通過以下簡單的例子來理解代理是如何工作的:
const userInfo = {
firstName: "fotis",
age: 35,
};
const handler = {
get(target, property) {
if (property === "firstName") {
const name = target[property]
return name.charAt(0).toUpperCase() + name.slice(1);
}
if (property === "age") {
return '--'
}
return target[property]
},
};
const proxy = new Proxy(userInfo, handler);
console.log(proxy.firstName) // "Fotis"
console.log(proxy.age) // "--"
處理器內部的get方法被稱為陷阱,每次訪問對象的屬性時都會被調用。以類似的方式,可以定義一個設定的陷阱:
const userInfo = {
firstName: "Fotis",
age: 35,
};
const handler = {
set(target, prop, value) {
if (prop === "age") {
if (!Number.isInteger(value)) {
throw new TypeError("The age is not an integer");
}
if (value > 200) {
throw new RangeError("The age seems invalid");
}
}
target[prop] = value;
return true;
},
};
const proxy = new Proxy(userInfo, handler);
proxy.age = 12 // OK
proxy.age = 300 // Error: The age seems invalid
這正是 Vue 3 響應性背后的理念。當使用 reactive 助手聲明一個變量時,會使用一個 proxy. 來跟蹤任何變化。
function reactive(obj) {
return new Proxy(obj, {
get(target, key) {
track(target, key)
return target[key]
},
set(target, key, value) {
target[key] = value
trigger(target, key)
}
})
}
當然,響應式助手的實際實現更為復雜,能處理邊緣情況,但其核心仍然使用proxy。
以上的片段解釋了為什么將響應性變量解構或重新分配給本地變量后,它就不再具有反應性,因為它不再觸發源對象上的 get/set proxy 陷阱。
這看起來像是一個完美的解決方案,可以使所有事物都變成響應式。但是有個問題!根據定義,proxy只適用于復雜類型。這些包括對象、數組、映射和集合。要使一個原始類型變得反應靈敏,我們仍然需要使用代理,但首先我們必須將其包裝在一個對象中。
function ref(value) {
const refObject = {
get value() {
track(refObject, 'value')
return value
},
set value(newValue) {
value = newValue
trigger(refObject, 'value')
}
}
return refObject
}
這解釋了為什么必須在 script setup 中使用煩人的 .value 。而且,再次重構或重新分配給本地變量也是行不通的。
總結
那么,為什么需要 Ref 和 Reactive 的答案是:Proxy。對于復雜類型,它們可以直接使用,但對于原始類型,需要創建一個代理對象。
本文轉載自微信公眾號「大遷世界」,可以通過以下二維碼關注。轉載本文請聯系大遷世界公眾號。