您好,登錄后才能下訂單哦!
這篇文章主要講解了“Vue3響應式的ref與reactive怎么使用”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“Vue3響應式的ref與reactive怎么使用”吧!
ref:定義基本數據類型、引用數據類型的響應式
。也就是說ref(value),這個value類型可以是基本數據類型,也可以是引用數據類型,但是在js中使用時必須以屬性.value
格式使用,在template中可以直接調用數據。
<template>
<div>
<div><button @click="changeValue">修改</button></div>
<div>
<p>當前strRef:{{ strRef }}</p>
<p>當前objRef:姓名:{{ objRef.name }} 愛好:{{ objRef.hobboy }}</p>
<p>當前arrRef:{{ arrRef }}</p>
</div>
</div>
</template>
<script>
import { defineComponent, ref, shallowRef } from 'vue'
export default defineComponent({
setup () {
const strRef = ref('sapper');// 基本數據類型
const arrRef = ref([1, 3, 2]);// 數組類型
const objRef = ref({ // 對象類型
name: 'sapper',
hobboy: ['吉他', '原神']
})
const changeValue = () => {
strRef.value = '工兵';
arrRef.value[1] = 4;
objRef.value.hobboy[1] = '滑冰';
}
return {strRef,objRef,arrRef,changeValue}
}
})
</script>
reactive:定義引用類型數據的響應式,不支持基本數據類型
,如果需要寫基本數據類型只能是放在對象中,也就是說reactive(value),這個value類型必須是引用類型。
<template>
<div>
<div><button @click="changeValue">修改</button></div>
<div>
<div>當前objReactive:
<br/>
姓名:{{ objReactive.name }}<br/>
愛好:{{ objReactive.hobboy }}
</div>
<div>當前arrReactive:{{ arrReactive }}</div>
</div>
</div>
</template>
<script>
import { defineComponent, reactive } from 'vue'
export default defineComponent({
setup () {
const arrReactive = reactive([1, 3, 2]);// 數組類型
const objReactive = reactive({ // 對象類型
name: 'sapper',
hobboy: ['吉他', '原神']
})
const changeValue = () => {
arrReactive[1] = 4;
objReactive.name = '工兵';
objReactive.hobboy[1] = '滑冰';
}
return {objReactive,arrReactive,changeValue}
}
})
</script>
從上面兩個例子中我們可以看出不管什么類型數據,ref都需要以.value
來調用ref定義的數據,對于引用數據類型來看,我們可以看出代碼不美觀,所以一般對于引用類型數據,都推薦使用reactive來定義;對于基本數據類型,可以使用ref也可以使用reactive來定義。既然到了這里我們都了解了ref和reactive的運用區別了,那么我們繼續來一起探討一下它們的響應原理又有什么區別?
從上面的例子,我們先打印看一下基本數據類型(strRef)、引用數據類型(arrRef、ObjRef)的ref內部封裝結構是什么樣的?如下三圖所示
從上面圖片可以看出,不管是什么類型的數據,對于ref封裝數據都是一個RefImpl對象,reference implement
的簡寫,是引用實現的意思,每個RefImpl對象都有6個屬性:
dep:是一個Set類型的數據,用來存儲當前的ref值收集的依賴。
_ v _ isRef :標記位,只要被ref定義了,都會標識當前數據為一個Ref,也就是它的值標記為true。
_ v _ isShallow:判斷是否是shallowRef定義的數據。
與ref不同的是,當使用shallowRef為引用類型創建響應性時,修改深層屬性,不具備響應性。只有對.value的引用時才觸發。
const state = shallowRef({ count: 1 })
// 不會觸發更改
state.value.count = 2
// 會觸發更改
state.value = { count: 2 }
_ rawValue:用于保存當前ref值對應的原始值
,如果傳遞的參數是對象
,它就是用于保存轉化前的原始值
,否則_ value與_ rawValue相同。
_ value:用于保存ref當前值
,如果傳遞的參數是對象
,它就是用于保存經過reactive函數轉化后的值
,否則_ value與_ rawValue相同。從上面例子我們可以發現,對于引用類型的數據,它的值就是一個proxy對象,這其實就是reactive封裝數據后對象(后面會說)。我們先看一下下圖,發現_ rawValue就是沒有做響應性處理的原始值,在看看_ value是一個proxy對象就是做了reactive響應處理的值。
_ rawValue與_ value就是為了區分引用類型數據是否做響應式處理。
value:保存的是當前的值。
既然我們清楚了ref給數據封裝了什么屬性,接下來開始探討源碼究竟給怎么給上面6個屬性進行賦值的:
ref函數:Vue3向開發者暴露的是ref函數,其實它就是封裝了一個createRef函數。
export function ref(value?: unknown) {
return createRef(value, false)
}
createRef函數:有兩個參數,一個是要做響應處理的數據
,一個是判斷數據是否為shallowRef定義的數據
。它主要做的事情就是判斷當前rawValue(暫時沒有做響應處理的數據)是否為ref類型數據、創建RefImpl實例對象。
function createRef(rawValue: unknown, shallow: boolean) {
if (isRef(rawValue)) {
return rawValue
}
return new RefImpl(rawValue, shallow)
}
RefImpl類:創建RefImpl類給_ rawValue和_ value屬性賦值,判斷當前定義的ref數據是否為shallowRef定義的數據,然后獲取響應性值時對數據依賴進行收集并返回_ value,修改響應式值時修改并通知依賴更新。
ref定義的數據為什么需要帶.value調用數據? 就是
因為RefImpl類暴露給實例對象的get、set方法是value
,所以在調用的時候,需要帶上。
其實,RefImpl實例關鍵就在于trackRefValue(this)
和triggerRefValue(this, newVal)
的兩個函數的處理,我們大概也知道它們就是依賴收集、依賴更新。這里就不一一探討。
上面也說了reactive封裝數據的用法,它只支持傳入引用類型數據(數組、對象),如果需要在reactive中使用基礎類型只能放在對象中。既然這樣我們來探討一下reactive函數究竟做了什么?
const arrReactive = reactive([1, 3, 2]);// 數組類型
const objReactive = reactive({ // 對象類型
name: 'sapper',
hobboy: ['吉他', '原神']
})
const changeValue = () => {
arrReactive[1] = 4;
objReactive.name = '工兵';
objReactive.hobboy[1] = '滑冰';
console.log('arrReactive',arrReactive);
console.log('objReactive',objReactive);
}
從上圖可以看出,使用reactive封裝的數據返回的都是一個proxy對象,proxy就是代理,如把一個對象代理到另一個對象,好比如房子所有者,代理房子給二手房東銷售,二手房東就可以擁有房子銷售權利。從上圖我們可以看到Proxy對象有三個屬性:
[[Handler]]: 創建Proxy對象傳入的第二個參數,是對當前需要代理的目標target進行一些相關配置處理。
[[Target]]:需要代理的目標target,也就是被代理的目標。
[[IsRevoked]]:表示是否可撤銷,生成可撤銷的proxy對象用Proxy.revocable()方法。 那么Proxy對象可以做什么?我們看看下面例子:
const houseOwner = {home:'房源',price:1200,type:'一房一廳'};
const proxyOwner = new Proxy(houseOwner,{
get:function (target,key){
console.log(`${key}屬性被訪問!`)
return target[key];
},
set:function(target,key,value){
if(target[key]===value){
return;
}
target[key] = value;
return target[key];
},
})
console.log(proxyOwner);
proxyOwner.price = 1300;// 對被代理對象的修改
proxyOwner.remark = '采光點好!';
console.log(proxyOwner.price);// price屬性被訪問
從這個例子,可以看出Proxy對象的第二個參數給代理目標帶上相關屬性:set方法、get方法,再回到reactive封裝的數據中,數據的Handler屬性給數據帶上了五個屬性:deleteProperty
、get
、set
、has
、ownKeys
。這五個屬性怎么來的?我們一起探討一下Vue3的源碼實現:
// 源碼位置:core-main/packages/reactivity/src/reactive.ts
// Vue3中暴露給開發者的是reactive方法
export function reactive(target: object) {
// 判斷target是否只讀,是就不做處理
if (isReadonly(target)) {
return target
}
return createReactiveObject(
target,
false,
mutableHandlers,
mutableCollectionHandlers,
reactiveMap
)
}
createReactiveObject函數主要為了創建Proxy實例對象,參數傳了五個屬性: target
(目標數據)、isReadonly
(target是否只讀)、mutableHandlers
(ProxyHandler)、mutableCollectionHandlers
(ProxyHandler類型)、proxyMap
(數據集合)。我們先了解一波createReactiveObject函數:
ReactiveFlags:響應式數據標記。
export const enum ReactiveFlags {
SKIP = '__v_skip',// 標記對象不可進行代理
IS_REACTIVE = '__v_isReactive',// 是否是Reactive封裝的
IS_READONLY = '__v_isReadonly',// 是否只讀
IS_SHALLOW = '__v_isShallow',// 是否是shallowRef封裝的
RAW = '__v_raw'// 是否是proxy原始的target
}
TargetType:target的數據類型。
const enum TargetType {
INVALID = 0,
COMMON = 1,// Array、Object類型
COLLECTION = 2 // Set、Map、WaekMap、WeakSet類型
}
baseHandlers:對于Array、Object類型數據,Proxy實例的第二個參數。傳入的baseHandlers就是mutableHandlers
。這個函數主要是為了給Proxy對象帶上五個屬性。
// 源碼位置:core-main/packages/reactivity/src/baseHandlers.ts
export const mutableHandlers: ProxyHandler<object> = {
// createGetter() 主要實現依賴收集和Reflect.set(target, key, value, receiver)
get,
// createSetter() 主要實現通知依賴更新和Reflect.get(target, key, receiver)
set,
// deleteProperty() 主要是刪除target的指定key的屬性Reflect.deleteProperty(target, key)
deleteProperty,
// has() 主要是判斷target是否存在指定key的屬性,Reflect.has(target, key)
has,
// ownKeys() 主要是獲取target的key數組,Reflect.ownKeys(target)
ownKeys
}
collectionHandlers:對于Set、Map、WaekMap、WeakSet類型數據,Proxy實例的第二個參數。傳入的baseHandlers就是mutableCollectionHandlers
。mutableCollectionHandlers主要是對 set、map、weakSet、weakMap 四種類型的對象進行劫持。
// 源碼位置:core-main/packages/reactivity/src/mutableCollectionHandlers.ts
export const mutableCollectionHandlers: ProxyHandler<CollectionTypes> = {
get: /*#__PURE__*/ createInstrumentationGetter(false, false)
}
function createInstrumentationGetter(isReadonly: boolean, shallow: boolean) {
const instrumentations = shallow?
isReadonly? shallowReadonlyInstrumentations: shallowInstrumentations
: isReadonly? readonlyInstrumentations: mutableInstrumentations
return (target: CollectionTypes,key: string | symbol,receiver: CollectionTypes) => {
...
return Reflect.get(
hasOwn(instrumentations, key) && key in target? instrumentations:target,
key,
receiver
)
}
}
感謝各位的閱讀,以上就是“Vue3響應式的ref與reactive怎么使用”的內容了,經過本文的學習后,相信大家對Vue3響應式的ref與reactive怎么使用這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。