reactive reactive 創建一個深層的對象的響應式代理,即對象根屬性以及嵌套對象的屬性都是響應式的。如果使用 ES6 結構賦值,就會使得這個對象的響應式代理第一層(根屬性)屬性失去響應式,但其嵌套下的對象屬性還是響應式的。 shallowReactive 會創建淺層的對象的響應式代理,只 ...
reactive
reactive
創建一個深層的對象的響應式代理,即對象根屬性以及嵌套對象的屬性都是響應式的。如果使用 ES6 結構賦值,就會使得這個對象的響應式代理第一層(根屬性)屬性失去響應式,但其嵌套下的對象屬性還是響應式的。
shallowReactive
會創建淺層的對象的響應式代理,只有第一層(根屬性)屬性有響應式,其嵌套對象的屬性不是響應式。
// 解構賦值
const { foo, bar } = { ...reactive({ foo: 1, bar: { val: 1 } }) };
<div>foo: {{ foo }}</div>
<button @click="foo++">Change foo</button>
<div>bar val: {{ bar.val }}</div>
<button @click="bar.val++">Click bar val</button>
如上圖所示,foo 只有在 bar.val
響應式更新之後才更新。被解構賦值之後,foo 是根屬性,失去了響應式;bar 是嵌套對象,其屬性還有響應式。
toRef
toRef
是基於響應式對象上的一個屬性,創建一個對應的 ref。這裡有非常重要的註意點,“響應式”、“對象”。toRef
操作的是一個響應式數據,且數據類型是對象,而不是一個普通對象,即便控制台不報錯,也會失去它的意義。
const obj = {
foo: {
bar: 1
}
};
const state = toRef(obj, "foo");
function change() {
state.value.bar++;
console.log(state.value.bar, obj.foo.bar);
}
<div>obj: {{ obj.foo.bar }}</div>
<div>foo: {{ state.bar }}</div>
<button @click="change">Change foo bar</button>
如下圖所示,頁面不發生更新:
但 state
確實是 Ref 類型:
也就是說,toRef
操作的數據不能是普通對象的屬性。
toRef 作用是什麼?
延續響應式能力
下麵是官方文檔給出的示例,左看右看、上看下看都沒看出個啥特別的。謎語人吧這是?
const state = reactive({
foo: 1,
bar: 2
})
const fooRef = toRef(state, 'foo')
// 更改該 ref 會更新源屬性
fooRef.value++
console.log(state.foo) // 2
// 更改源屬性也會更新該 ref
state.foo++
console.log(fooRef.value) // 3
❓那麼 toRef
有什麼用呢?前面說到 reactive 被解構賦值之後第一層(根屬性)失去了響應式,而 toRef
可以讓其繼續保持響應式。
toRef
當作 ref
函數創建一個響應式數據不是響應式的,頁面不更新,前面圖2 中已經說明瞭。toRef
是延續響應式能力,不是創建響應式數據。
對第一節中的例子進行修改:
// 在 reactive 中包裹了 toRefs
const { foo, bar } = { ...toRefs(reactive({ foo: 1, bar: { val: 1 } })) };
圖4 與 圖1 進行對比,foo 確確實實是響應式的,頁面也發生了變化。不再因為 bar.val
更新而更新。
toRef 與 toRefs 的區別就是多了一個 s,即批量延續 reactive 的響應式能力。
轉換 prop 為 Ref 類型
官方文檔中有提到關於 prop 與 toRef 結合使用的案例,說非常有用。有些函數需要的參數類型就是 Ref,比如 useRefHistory,就需要傳遞 Ref 類型的數據:
組件 prop 不是一個 Ref 類型的數據:
console.log(isRef(props.foo)); // => false
因此,用 toRef
轉換類型,與原始數據保持同步:
useRefHistory(toRef(props, "foo"));
總結
toRef
是延續響應式,不是創建響應式數據,不能等同於 ref
函數。為何是延續響應式,需要查閱源碼方可知曉。本博客只是從表現中得到的結論,沒有從原理上進行總結,屬於經驗之談。
toRef
只能基於響應式數據進行操作,對普通的對象進行操作得到的數據不是響應式的。