免費(fèi)企業(yè)建站源代碼搜索引擎廣告推廣
目錄
- reactive
- reactive的實(shí)現(xiàn)原理
- 使用reactive的注意事項(xiàng)
- ref
- ref的實(shí)現(xiàn)原理
- 使用ref的注意事項(xiàng)
- toRef和toRefs
- ref和reactive的使用比較
reactive
reactive用于創(chuàng)建響應(yīng)式對象,它返回一個對象的響應(yīng)式代理。即:它返回的對象以及其中嵌套的對象都會通過 Proxy 包裹;當(dāng)響應(yīng)式對象被訪問時,觸發(fā)getter方法;當(dāng)響應(yīng)式對象被修改時,觸發(fā)setter方法。在使用響應(yīng)式對象時,我們可以像普通對象一樣訪問和修改數(shù)據(jù)。
使用reactive的示例代碼
<template><div> {{ state.name }} --- {{ state.age }}</div>
</template>
<script setup>
import { reactive } from 'vue';
const state = reactive({name: 'jack',age: 22
})
</script>
<style scoped>
</style>
reactive的實(shí)現(xiàn)原理
reactive是利用ES6的Proxy對象來實(shí)現(xiàn)的。當(dāng)我們使用reactive函數(shù)對一個對象進(jìn)行響應(yīng)式處理時,Vue3會創(chuàng)建一個Proxy,攔截該對象的所有屬性的讀取和修改操作,從而實(shí)現(xiàn)監(jiān)聽屬性的變化,并在變化時觸發(fā)相關(guān)的響應(yīng)式更新。
reactive實(shí)現(xiàn)原理的簡單示意代碼如下:
function reactive(obj) {if(typeof obj !== 'object' || obj === null) {return obj;}// 防止響應(yīng)式重復(fù)包裹if(obj.__v_reactive) {return obj;}const observed = new Proxy(obj, {get(target, key, receiver) {// 收集依賴track(target, TrackOpTypes.GET, key);// 遞歸獲取嵌套屬性const res = Reflect.get(target, key, receiver);return isObject(res) ? reactive(res) : res;},set(target, key, value, receiver) {// 更新屬性值const oldValue = Reflect.get(target, key, receiver);let result = true;if(oldValue !== value) {result = Reflect.set(target, key, value, receiver);// 觸發(fā)更新trigger(target, TriggerOpTypes.SET, key, value, oldValue);}return result;},deleteProperty(target, key) {const hasKey = hasOwn(target, key);const oldValue = target[key];const result = Reflect.deleteProperty(target, key);if(hasKey && result) {// 觸發(fā)更新trigger(target, TriggerOpTypes.DELETE, key, undefined, oldValue);}return result;}});// 標(biāo)記為響應(yīng)式對象observed.__v_reactive = true; return observed;
}
上述代碼中,reactive函數(shù)接收一個對象 obj,如果 obj 不是對象或?yàn)?null,返回原值。如果 obj 已經(jīng)被處理為響應(yīng)式,則直接返回該響應(yīng)式對象。
使用reactive的注意事項(xiàng)
-
reactive只能處理對象和數(shù)組,如果傳入非對象或數(shù)組的參數(shù)將會直接返回,不會進(jìn)行響應(yīng)式處理。
-
對于給定的對象,reactive將會遞歸收集其中所有子屬性的依賴關(guān)系,因此在實(shí)際開發(fā)中,盡量不要嵌套過深,否則可能會影響性能。
-
reactive處理后的對象,不能直接用于解構(gòu)賦值操作,建議采用Vue3提供的toRefs函數(shù)將響應(yīng)式對象轉(zhuǎn)換成普通對象后再進(jìn)行操作。
-
在組件的setup函數(shù)中,需要使用ref或reactive對數(shù)據(jù)進(jìn)行響應(yīng)式處理后才能使用,在函數(shù)外部創(chuàng)建的響應(yīng)式對象也必須在組件的setup函數(shù)中使用才能確保響應(yīng)式生效。
ref
關(guān)于ref的相關(guān)特性,我在前面的博客中有講過其用于注冊元素或子組件的引用時的用法,這里就不在充分講了,只對前面博客沒有提到的響應(yīng)式進(jìn)行探討。
ref 接受一個內(nèi)部值,返回一個響應(yīng)式的、可更改的 ref 對象,此對象只有一個指向其內(nèi)部值的屬性 .value。它將一個基本類型數(shù)據(jù)包裝為響應(yīng)式對象。
ref 對象是可更改的,我們可以通過 .value 屬性來修改它的值。它也是響應(yīng)式的,即所有對 .value 的操作都將被追蹤,并且寫操作會觸發(fā)與之相關(guān)的副作用。
如果將一個對象賦值給 ref,那么這個對象將通過 reactive() 轉(zhuǎn)為具有深層次響應(yīng)式的對象。這也意味著如果對象中包含了嵌套的 ref,它們將被深層地解包。
ref的實(shí)現(xiàn)原理
ref是基于基于Vue 3中的reactive和proxy兩個API來實(shí)現(xiàn)的,proxy通過創(chuàng)建攔截器對象來在對象上設(shè)置自定義行為。它用于攔截對ref對象的讀取和寫入操作,以便在改變ref值時通知Vue響應(yīng)式系統(tǒng)來更新視圖。
ref實(shí)現(xiàn)原理的簡單示意代碼如下:
function ref(value) {return reactive({value,get unbox() {return this.value}})
}
在這里,我們通過將value作為響應(yīng)式對象的一個屬性,從而使得value變?yōu)轫憫?yīng)式。同時,我們通過unbox屬性提供了一個獲取value的值的便捷方法。
使用ref的注意事項(xiàng)
-
ref只能用于包裝簡單類型的數(shù)據(jù),如字符串、數(shù)字、布爾值等獨(dú)立的基本數(shù)據(jù)類型,或者對象、數(shù)組、函數(shù)等引用類型的數(shù)據(jù)。不建議將ref用于包裝復(fù)雜的嵌套數(shù)據(jù)結(jié)構(gòu),因?yàn)檫@會增加處理和維護(hù)的復(fù)雜性。
-
在組件內(nèi)使用ref時,建議在setup()函數(shù)內(nèi)創(chuàng)建ref成員變量,并在組件模板中使用模板引用(template refs)來引用它。
-
ref只能用于包裝可變變量,不應(yīng)用于包裝不可變變量或常量,因?yàn)檫@樣會導(dǎo)致無法更新變量的值。
-
在對ref對象進(jìn)行操作時,應(yīng)該使用.value屬性來訪問其內(nèi)部的響應(yīng)式值,而不是直接操作ref對象本身。
-
不要在ref對象上定義額外的屬性或方法,因?yàn)檫@些屬性和方法不會被響應(yīng)式系統(tǒng)跟蹤,也不會觸發(fā)視圖更新。如果需要在ref對象上定義屬性或方法,應(yīng)該使用reactive對象來包裝它們。
toRef和toRefs
toRef和toRefs是vue中兩個非常重要的工具函數(shù)。它們可以將一個響應(yīng)式對象的屬性,轉(zhuǎn)換成一個Ref對象或者Ref對象集合,使得這些屬性可以在組件中被使用。
-
toRef:toRef函數(shù)將響應(yīng)式對象的其中一個屬性轉(zhuǎn)換成一個Ref對象。
toRef的一個簡單示例
<template><div> {{ nameRef}} </div> </template> <script setup> import { reactive, toRef } from 'vue' const state = reactive({name: 'Vue 3',version: '3.0.0' }) const nameRef = toRef(state, 'name') </script> <style scoped> </style>
-
toRefs:toRefs函數(shù)將一個響應(yīng)式對象的全部屬性轉(zhuǎn)換成Ref對象集合。
toRefs的一個簡單示例
<template><div> {{ refs.name }} ---{{ refs.version }}</div> </template> <script setup> import { reactive, toRefs } from 'vue'const state = reactive({name: 'Vue 3',version: '3.0.0' })const refs = toRefs(state) </script> <style scoped> </style>
ref和reactive的使用比較
Ref和Reactive都是響應(yīng)式對象。它們的區(qū)別在于:
Ref是一個基本類型的響應(yīng)式容器,通過.value訪問,適用于基本類型或者簡單對象的響應(yīng)式數(shù)據(jù)。
Reactive是一個對象級別的響應(yīng)式容器,適用于復(fù)雜的對象或者數(shù)組的響應(yīng)式數(shù)據(jù)。
下面是一個示例代碼,展示了Ref和Reactive的區(qū)別和使用場景:
<template><div> {{ count }} ---{{ doubleCount }} <br>{{ state.count }} ---{{ state.doubleCount }}</div>
</template>
<script setup>
import { ref, reactive,watch } from 'vue'
// 1. Ref示例代碼
const count = ref(0)
const doubleCount = ref(0)
watch(count, () => {doubleCount.value = count.value * 2
})
// 2. Reactive示例代碼
const state = reactive({count: 0,doubleCount: 0
})
watch(() => state.count, () => {state.doubleCount = state.count * 2
})
</script>
<style scoped>
</style>
上述代碼中,我們通過Ref對象和Reactive對象來實(shí)現(xiàn)同一個數(shù)據(jù)的響應(yīng)式處理??梢钥闯?#xff0c;Ref對象使用簡單,適用于單一的基本類型數(shù)據(jù),而Reactve對象則復(fù)雜些,適用于復(fù)雜的對象和數(shù)組數(shù)據(jù)。
OK,關(guān)于vue3中的reactive、ref、toRef和toRefs相關(guān)的使用方法就介紹到這里,喜歡的小伙伴點(diǎn)贊關(guān)注加收藏哦!