Vue3.0系列(Composition API 的補充)
阿新 • • 發佈:2021-01-31
上一篇我們說了ref 和 reactive建立資料,下面來做一些補充
1…遞迴監聽和非遞迴監聽
1.1 遞迴監聽
1. 預設情況下, 無論是通過ref還是reactive都是遞迴監聽
每一層都監聽
<template> <div> <p>{{state.a}}</p> <p>{{state.gf.b}}</p> <p>{{state.gf.f.c}}</p> <p>{{state.gf.f.s.d}}</p> <button @click="myFn">按鈕</button> </div> </template> <script> import {reactive} from 'vue'; // import {ref} from 'vue'; export default { name: 'App', setup() { let state = reactive({ a:'a', gf:{ b:'b', f:{ c:'c', s:{ d:'d' } } } }); function myFn() { state.a = '1'; state.gf.b = '2'; state.gf.f.c = '3'; state.gf.f.s.d = '4'; console.log(state); console.log(state.gf); console.log(state.gf.f); console.log(state.gf.f.s); } return {state, myFn} } } </script>
2.遞迴監聽存在的問題
如果資料量比較大, 非常消耗效能
列印後,發現每一層物件都被包裝為了Proxy物件,
如果資料量比較大, 非常消耗效能
2.2 非遞迴監聽
使用shallowReactive
和shallowRef
shallowReactive:
<script> // 3.非遞迴監聽 import {shallowReactive} from 'vue'; export default { name: 'App', setup() { let state = shallowReactive({ // let state = ref({ a:'a', gf:{ b:'b', f:{ c:'c', s:{ d:'d' } } } }); function myFn() { state.a = '1'; state.gf.b = '2'; state.gf.f.c = '3'; state.gf.f.s.d = '4'; console.log(state); console.log(state.gf); console.log(state.gf.f); console.log(state.gf.f.s); } return {state, myFn} } } </script>
再次列印輸出結果,發現只有第一層被封裝為了Proxy物件
,
但是第2, 3,4層資料為什麼也發生了變化呢?
因為修改了第一層,它就去修改UI了
shallowRef:
注意點:
- 如果是通過shallowRef建立資料,
那麼Vue監聽的是.value的變化, 並不是第一層的變化 - Vue3只提供了triggerRef方法, 沒有提供triggerReactive方法
- 所以如果是reactive型別的資料, 是無法主動觸發介面更新的
triggerRef(state);
2.toRow 和 markRow
2.1 toRow
- 從Reactive 或 Ref中得到原始資料
let obj = {name:‘lnj’, age:18};let state = reactive(obj);
let obj2 = toRaw(state);- toRaw作用 :做一些不想被監聽的事情(提升效能)
例子:
ref/reactive資料型別的特點:
- 每次修改都會被追蹤, 都會更新UI介面, 但是這樣其實是非常消耗效能的
- 所以如果我們有一些操作不需要追蹤, 不需要更新UI介面, 那麼這個時候,
- 我們就可以通過
toRaw
方法拿到它的原始資料, 對原始資料進行修改, 這樣就不會被追蹤, 這樣就不會更新UI介面, 這樣效能就好了
import {reactive, toRaw} from 'vue';
export default {
name: 'App',
setup() {
let obj = {name:'lnj', age:18};
// state和obj的關係:
// 引用關係, state的本質是一個Proxy物件, 在這個Proxy物件中引用了obj
let state = reactive(obj);
let obj2 = toRaw(state);
function myFn() {
// 如果直接修改obj, 那麼是無法觸發介面更新的
// 只有通過包裝之後的物件來修改, 才會觸發介面的更新
obj2.name = 'zs';
console.log(obj2); // {name: "zs", age: 18}
console.log(state); // {name: "zs", age: 18}
}
return {state, myFn}
}
}
上面的例子是,toRow獲取 Reactive
型別的原始資料,
如果toRow要獲取 ref
型別的原始資料,
注意點:
- ref本質: reactive
ref(obj) -> reactive({value: obj}) - 注意點: 如果想通過toRaw拿到ref型別的原始資料(建立時傳入的那個資料)
那麼就必須明確的告訴toRaw方法, 要獲取的是.value
的值
因為經過Vue處理之後, .value中儲存的才是當初建立時傳入的那個原始資料
let obj = {name:'lnj', age:18};
let state = ref(obj);
let obj2 = toRaw(state.value);
2.2 markRow
markRaw
將資料標記為永遠不能追蹤的資料
一般在編寫自己的第三方庫時使用
import {reactive, markRaw} from 'vue';
export default {
name: 'App',
setup() {
let obj = {name: 'lnj', age: 18};
obj = markRaw(obj);
let state = reactive(obj);
function myFn() {
state.name = 'zs';
}
return {state, myFn}
}
}
3. toRef 和 toRefs
- toRef
建立一個ref型別資料, 並和以前的資料關聯 - toRefs
批量建立ref型別資料, 並和以前資料關聯 - toRef和ref區別
ref
創建出來的資料和以前無關
(複製)
toRef
-創建出來的資料和以前的有關
(引用)
ref-資料變化會自動更新
介面
toRef-資料變化不會自動更新
介面
<script>
import {ref, toRef} from 'vue';
export default {
name: 'App',
setup() {
let obj = {name:'lnj'};
/*
ref(obj.name) -> ref(lnj)
-> reactive({value:lnj})
* */
// ref->複製
// let state = ref(obj.name);
// toRef->引用
/*
ref和toRef區別:
ref->複製, 修改響應式資料不會影響以前的資料
toRef->引用, 修改響應式資料會影響以前的資料
ref->資料發生改變, 介面就會自動更新
toRef->資料發生改變, 介面也不會自動更新
toRef應用場景:
如果想讓響應式資料和以前的資料關聯起來, 並且更新響應式資料之後還不想更新UI, 那麼就可以使用toRef
* */
let state = toRef(obj, 'name');
function myFn() {
state.value = 'zs';
console.log(obj);
console.log(state);
}
return {state, myFn}
}
}
</script>