Vue3中關于ref和reactive的區(qū)別分析
一、reactive
數據類型
reactive()
可用于創(chuàng)造一個響應式對象,它接受一個參數,這個參數的類型是一個重點,接下來我們先看看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主要是調用createReactiveObject
函數來創(chuàng)建reactive對象,從源碼里可以看到,該函數會首先判斷reactive()
傳入的參數是不是一個對象,如果不是則不做任何處理,直接返回原值,同時開發(fā)環(huán)境下會在控制臺輸出一句警告。所以嚴格上來說,reactive()
并不是像有些人說的不能傳入基本類型的參數,它可以傳,只是這種數據會失去響應式。
let name = reactive('張三') setTimeout(() => { name = '李四' console.log(name, 'name') // 李四 }, 3000) <template> <h1>{{ name }}</h1> </template>
上面模板里仍然顯示的是張三,因為name沒有響應式不會觸發(fā)視圖更新。
原始數據與響應式數據
我們可以先定義一個原始對象,再將對象傳入reactive()
,此時原始對象和響應式對象會互相干擾。
let data = { name: '張三' } // 原始對象 let state = reactive(data) setTimeout(() => { state.name = '李四' console.log(data.name) // 李四 }, 2000)
修改響應式對象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的話,建議始終是對響應式對象進行操作而不是原始數據。
二、ref
數據類型
export function ref(value?: unknown) { return createRef(value, false) }
從源碼里可以知道,ref()
接受一個參數,參數可以是任意類型
,這也是ref與reactive的區(qū)別之一,不管是基本類型還是引用類型ref
都具備響應式,另外ref
要通過.value
進行取值。
let name = ref('張三') // 可以是基本類型 // 也可以是引用類型 let user = ref({ name: '張三', age: 18 }) console.log(name.value) console.log(user.value)
原始數據與響應式數據
ref
與reactive
一樣,修改原始數據或響應式數據都會同步改變對方的值,且在修改原始對象時都無法觸發(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
內部會調用toReactive
函數,如果不是基本類型的數據,會將其轉換成reactive
。
可重新賦值對象
使用reactive
時,對響應式對象重新賦值是會失去響應式的。
let state = reactive({ name: '張三' }) setTimeout(() => { state = { name: '李四'} console.log(state.name) // 李四,數據變更了但視圖不會更新 }, 2000)
ref
則沒有這種問題。
let state = ref({ name: '張三' }) setTimeout(() => { state.value = { name: '李四'} console.log(state.value.name) // 數據變更,同時視圖也會更新 }, 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: true
watch也會觸發(fā),而ref則需要手動加上。
小結
- 對于響應式而言,ref支持對象類型和基本類型,而reactive只支持對象類型
- 當ref是對象類型的時候,本質上也是一個reactive
- 對象類型的ref和reactive,其響應式底層原理都是Proxy
以上就是Vue3中關于ref和reactive的區(qū)別分析的詳細內容,更多關于vue3 ref 和reactive的資料請關注腳本之家其它相關文章!
相關文章
element-ui復雜table表格動態(tài)新增列、動態(tài)調整行以及列順序詳解
這篇文章主要給大家介紹了關于element-ui復雜table表格動態(tài)新增列、動態(tài)調整行以及列順序的相關資料,文中通過代碼示例介紹的非常詳細,需要的朋友可以參考下2023-08-08淺析Proxy可以優(yōu)化vue的數據監(jiān)聽機制問題及實現思路
這篇文章主要介紹了淺析Proxy可以優(yōu)化vue的數據監(jiān)聽機制問題及實現思路,需要的朋友可以參考下2018-11-11vue2.0結合DataTable插件實現表格動態(tài)刷新的方法詳解
這篇文章主要介紹了vue2.0結合DataTable插件實現表格動態(tài)刷新的方法,結合具體項目實例形式分析了vue2.0結合DataTable插件實現表格動態(tài)刷新過程中遇到的問題與相應的解決方法,需要的朋友可以參考下2017-03-03Vue執(zhí)行方法,方法獲取data值,設置data值,方法傳值操作
這篇文章主要介紹了Vue執(zhí)行方法,方法獲取data值,設置data值,方法傳值操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-08-08