介紹
眾所周知,vue3 相較於 vue2 進行了很大提升,很大的一方面就是響應式原理上————使用了 Proxy。Proxy 可以先看看 阮一峰大大的教程,建議 15、16章節連起來看,那么如何去使用呢?
我們可以這樣的理解,reactive 和 ref 相當於一個語法糖,使用這兩個語法糖創建的變量就具備了響應式的功能,能自動的在頁面和數據之間進行驅動。可能有朋友不太理解,ref 在 vue2 中不是定義操作 DOM 的節點嗎?為什么這里能定義變量了,還是響應式的。這是因為 vue3 內部給它重新進行了賦能,大家先簡單這樣記下就好。
好,具體說下區別:
定義上:
- ref - 推薦定義基礎類型變量,這個時候內部是使用
Object.defineProperty
實現響應原理的,如果定義了 Object 類型變量,那么其內部還是指向 proxy 的,這點我們可以先打印看看
從 value 指向上我們可以看到內部 value、_value
的變更
- reactive - 推薦使用復雜變量,如 object,可從 ref 定義復雜變量內部還是指向 proxy,或 proxy 攔截復雜對象反向推到,這里放一張 vue3 官方網站上的 reactive 定義
function reactive<T extends object>(target: T): UnwrapNestedRefs<T>
可以看到可拓展對象還是指向的 object
使用方式上:
注意:這里如果沒有特指,使用范圍全部在 setup 內
- ref - 的賦值必須使用 .value,這點可從打印的圖片上可以看出,那同理,取值的話也要加一個 .value,不然指向不正確,來張圖:
但是 .value 取值的話一次還好,多次就比較麻煩,這里有一個簡化的 api——unref,同樣來張圖:
import { unref } from 'vue';
const aa = ref('haha');
console.log('aa', aa);
console.log('aa.value prev', aa.value);
aa.value = 'houhou';
console.log('aa.value next', aa.value);
console.log('unref(aa)', unref(aa));
- reactive - reactive 則沒這么麻煩,和正常的 object 一樣操作就好,沒有什么 .value,同樣來張圖:
import { reactive} from 'vue';
const cc = reactive({
a: 1,
b: 2,
c: 3
});
cc.a = 10;
cc.d = 12;
console.log('cc', cc);
console.log('cc.a', cc.a);
console.log('cc.d', cc.d);
可以看到正常的 object.key 這種形式,新增和修改都是能正常響應的(如更改的屬性 a 和 新增的屬性 d),來說說如果對它解構的話會怎樣,來張圖:
let { a } =cc;
console.log('a prev', a);
a = 15;
console.log('a next', a);
console.log('cc', cc);
可以看到,解構的變量不再具有響應式(a 改變,cc 並沒變),當然這種情況用到的不多,如果我們要改變一個對象的某個屬性,一般可通過 Object.assign(obj, {})
這種形式解決,這里說他只是為了引入 toRefs 這個 api——把 reactive 解構為一組具備響應式關系的 ref,同樣來張圖:
可以看到打印出來的變量 b 已經指向了 ObjectRefImpl
這個類,並看到 ``__v_isRef:、_key、_object、value``` 這幾個屬性,可以簡單的把它們理解為響應關聯,此時 b 這個變量就和 cc 這個對象關聯起來了,當改變 b 的值時,cc 同樣發生了變化,這樣有個好處就是,當我們在一個 reactive 里定義了很多變量時,如果在模板上一個一個 object.key 這種方式去寫,會很麻煩,也不美觀,這個時候就可以 toRefs 出去,直接寫 key 即可,這樣數據就具備了響應關聯,vue 就能在數據變化時自動更新頁面,我們來試下,同樣上圖:
// template
<ul>
<li>我是 cc 對象的屬性 a,{{ a }}</li>
<li>我是 cc 對象的屬性 b,{{ b }}</li>
<li>我是 cc 對象的屬性 c,{{ c }}</li>
</ul>
// setup
return {
...toRefs(cc)
};
最后
說得多還不如上手,大家動手練練哈哈