Vue3中關(guān)于ref和reactive的區(qū)別分析
一、reactive
數(shù)據(jù)類型
reactive()可用于創(chuàng)造一個響應(yīng)式對象,它接受一個參數(shù),這個參數(shù)的類型是一個重點,接下來我們先看看Vue3的源碼里是怎么處理的。
function createReactiveObject(
target: Target,
isReadonly: boolean,
baseHandlers: ProxyHandler<any>,
collectionHandlers: ProxyHandler<any>,
proxyMap: WeakMap<Target, any>
) {
if (!isObject(target)) {
if (__DEV__) {
console.warn(`value cannot be made reactive: ${String(target)}`)
}
return target
}
// ...
}Vue3主要是調(diào)用createReactiveObject函數(shù)來創(chuàng)建reactive對象,從源碼里可以看到,該函數(shù)會首先判斷reactive()傳入的參數(shù)是不是一個對象,如果不是則不做任何處理,直接返回原值,同時開發(fā)環(huán)境下會在控制臺輸出一句警告。所以嚴(yán)格上來說,reactive()并不是像有些人說的不能傳入基本類型的參數(shù),它可以傳,只是這種數(shù)據(jù)會失去響應(yīng)式。
let name = reactive('張三')
setTimeout(() => {
name = '李四'
console.log(name, 'name') // 李四
}, 3000)
<template>
<h1>{{ name }}</h1>
</template>上面模板里仍然顯示的是張三,因為name沒有響應(yīng)式不會觸發(fā)視圖更新。
原始數(shù)據(jù)與響應(yīng)式數(shù)據(jù)
我們可以先定義一個原始對象,再將對象傳入reactive(),此時原始對象和響應(yīng)式對象會互相干擾。
let data = { name: '張三' } // 原始對象
let state = reactive(data)
setTimeout(() => {
state.name = '李四'
console.log(data.name) // 李四
}, 2000)修改響應(yīng)式對象state.name的值,原始對象data.name也會同步變化。
反過來也是一樣,修改data.name,state.name也會同步變化,但需要注意的是:這種情況下雖然state.name發(fā)生了改變但視圖并不會更新。
let data = { name: '張三' }
let state = reactive(data)
setTimeout(() => {
data.name = '李四'
console.log(state.name) // 李四,但template里仍為張三
}, 2000)
</script>
<template>
<h1>{{ state.name }}</h1>
</template>所以如果你是通過定義一個對象再將對象傳入reactive的話,建議始終是對響應(yīng)式對象進行操作而不是原始數(shù)據(jù)。
二、ref
數(shù)據(jù)類型
export function ref(value?: unknown) {
return createRef(value, false)
}從源碼里可以知道,ref()接受一個參數(shù),參數(shù)可以是任意類型,這也是ref與reactive的區(qū)別之一,不管是基本類型還是引用類型ref都具備響應(yīng)式,另外ref要通過.value進行取值。
let name = ref('張三') // 可以是基本類型
// 也可以是引用類型
let user = ref({
name: '張三',
age: 18
})
console.log(name.value)
console.log(user.value)原始數(shù)據(jù)與響應(yīng)式數(shù)據(jù)
ref與reactive一樣,修改原始數(shù)據(jù)或響應(yīng)式數(shù)據(jù)都會同步改變對方的值,且在修改原始對象時都無法觸發(fā)視圖更新。
ref也可能是一種reactive
function createRef(rawValue: unknown, shallow: boolean) {
if (isRef(rawValue)) {
return rawValue
}
return new RefImpl(rawValue, shallow)
}
class RefImpl<T> {
private _value: T
private _rawValue: T
public dep?: Dep = undefined
public readonly __v_isRef = true
constructor(value: T, public readonly __v_isShallow: boolean) {
this._rawValue = __v_isShallow ? value : toRaw(value)
this._value = __v_isShallow ? value : toReactive(value)
}
get value() {
trackRefValue(this)
return this._value
}
set value(newVal) {
const useDirectValue =
this.__v_isShallow || isShallow(newVal) || isReadonly(newVal)
newVal = useDirectValue ? newVal : toRaw(newVal)
if (hasChanged(newVal, this._rawValue)) {
this._rawValue = newVal
this._value = useDirectValue ? newVal : toReactive(newVal)
triggerRefValue(this, newVal)
}
}
}通過源碼可以知道,ref是通過RefImpl這個類來創(chuàng)建的,而在RefImpl內(nèi)部會調(diào)用toReactive函數(shù),如果不是基本類型的數(shù)據(jù),會將其轉(zhuǎn)換成reactive。
可重新賦值對象
使用reactive時,對響應(yīng)式對象重新賦值是會失去響應(yīng)式的。
let state = reactive({ name: '張三' })
setTimeout(() => {
state = { name: '李四'}
console.log(state.name) // 李四,數(shù)據(jù)變更了但視圖不會更新
}, 2000)ref則沒有這種問題。
let state = ref({ name: '張三' })
setTimeout(() => {
state.value = { name: '李四'}
console.log(state.value.name) // 數(shù)據(jù)變更,同時視圖也會更新
}, 2000)使用watch監(jiān)聽ref對象需要deep
let state = ref({ name: '張三' })
setTimeout(() => {
state.value.name = '李四'
}, 2000)
watch(state, () => {
console.log(state.value.name)
}, { deep: true })reactive不加deep: truewatch也會觸發(fā),而ref則需要手動加上。
小結(jié)
- 對于響應(yīng)式而言,ref支持對象類型和基本類型,而reactive只支持對象類型
- 當(dāng)ref是對象類型的時候,本質(zhì)上也是一個reactive
- 對象類型的ref和reactive,其響應(yīng)式底層原理都是Proxy
以上就是Vue3中關(guān)于ref和reactive的區(qū)別分析的詳細(xì)內(nèi)容,更多關(guān)于vue3 ref 和reactive的資料請關(guān)注腳本之家其它相關(guān)文章!
- Vue3.0中Ref與Reactive的區(qū)別示例詳析
- vue3?中ref和reactive的區(qū)別講解
- 前端vue3中的ref與reactive用法及區(qū)別總結(jié)
- Vue3 的ref和reactive的用法和區(qū)別示例解析
- Vue3中ref和reactive的基本使用及區(qū)別詳析
- Vue3中ref和reactive的區(qū)別及說明
- vue3.0中ref與reactive的區(qū)別及使用場景分析
- vue3中reactive和ref的實現(xiàn)與區(qū)別詳解
- vue3 ref 和reactive的區(qū)別詳解
- vue3中ref和reactive的區(qū)別舉例詳解
相關(guān)文章
vue中集成省市區(qū)街四級地址組件的實現(xiàn)過程
我們在開發(fā)中常會遇到選擇地址的需求,有時候只需要選擇省就可以,有時候則需要選擇到市、縣,以至于鄉(xiāng)鎮(zhèn),甚至哪個村都有可能,下面這篇文章主要給大家介紹了關(guān)于vue中集成省市區(qū)街四級地址組件的相關(guān)資料,需要的朋友可以參考下2022-12-12
Vue3解析markdown并實現(xiàn)代碼高亮顯示的詳細(xì)步驟
Vue的markdown解析庫有很多,如markdown-it、vue-markdown-loader、marked、vue-markdown等,這篇文章主要介紹了Vue3解析markdown并實現(xiàn)代碼高亮顯示,需要的朋友可以參考下2022-07-07
vue element插件this.$confirm用法及說明(取消也可以發(fā)請求)
這篇文章主要介紹了vue element插件this.$confirm用法及說明(取消也可以發(fā)請求),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-10-10
vue中$refs, $emit, $on, $once, $off的使用詳解
這篇文章主要介紹了vue中$refs, $emit, $on, $once, $off的使用詳解,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-05-05

