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 只能基于回應式資料進行操作,對普通的物件進行操作得到的資料不是回應式的,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/547322.html
標籤:其他
上一篇:前端常見的十種布局
下一篇:萬字血書Vue—路由
