Vue3中reactive與ref函數(shù)使用場(chǎng)景
前言
如果你使用過(guò) Vue3,你知道的,在 Vue3 中有兩個(gè)非常常用的響應(yīng)式 API:reactive 和 ref。它們會(huì)把我們想要追蹤的數(shù)據(jù)變成響應(yīng)式。
而且我們?cè)谑褂脮r(shí)一直被告知 ref 用于創(chuàng)建基礎(chǔ)類型的響應(yīng)式,也可以創(chuàng)建引用類型的響應(yīng)式。而對(duì)于引用類型,底層也是轉(zhuǎn)換為 reactive 來(lái)進(jìn)行響應(yīng)式處理。那既然這樣為撒還需要 reactive ,全部使用 ref 不就行了嗎?
雖然 ref 創(chuàng)建的響應(yīng)式數(shù)據(jù)在腳本中需要通過(guò) .value 才能訪問(wèn)到呀!但是這里肯定影響不大。并且在模板中會(huì)自動(dòng)添加上 .value,所以模板中不需要通過(guò) .value 訪問(wèn)。
既然這二者基本沒(méi)撒差別,但是還是暴露了 reactive 這個(gè) API,難道有什么場(chǎng)景是 reactive 能做而 ref 做不了的?
簡(jiǎn)單了解 ref & reactive
我們先簡(jiǎn)單了解一下這兩個(gè) API。
reactive
返回對(duì)象的響應(yīng)式副本,響應(yīng)式轉(zhuǎn)換是“深層”的——它影響所有嵌套 property。我們一般這樣寫(xiě)。
const obj = reactive({ count: 0 })
并且可以直接使用。
const count = obj.count
ref
接受一個(gè)內(nèi)部值并返回一個(gè)響應(yīng)式且可變的 ref 對(duì)象。ref 對(duì)象僅有一個(gè) .value
property,指向該內(nèi)部值。 我們一般是這樣寫(xiě)。
const data = ref(xxx)
引用的時(shí)候,一般會(huì)通過(guò)data.value
的方式引用。
const dataValue = data.value
通過(guò)跟蹤 Vue3 的源代碼可以證明,當(dāng)我們調(diào)用 ref 方法來(lái)定義響應(yīng)式數(shù)據(jù)時(shí),當(dāng)參數(shù)為對(duì)象類型時(shí),其實(shí)里面用的是 reactive 方法。也就是說(shuō)上面的 data.value ,事實(shí)上是 reactive 方法創(chuàng)造出來(lái)的。
reactive 能做的 ref 也能做,并且還是用 reactive 做的
我們通過(guò)源碼來(lái)看看 ref 的源碼實(shí)現(xiàn)。
源碼分析版本:3.2.36
function ref(value) { return createRef(value, false); }
ref 函數(shù)跳轉(zhuǎn)到 createRef 函數(shù)。
function createRef(rawValue, shallow) { ... return new RefImpl(rawValue, shallow); }
createRef 函數(shù)返回的是 RefImpl 類的實(shí)例,換句話說(shuō),ref 創(chuàng)建出來(lái)的響應(yīng)式就是 RefImpl 實(shí)例對(duì)象。
const count = ref(1); console.log(count);
我們重點(diǎn)來(lái)看看這個(gè) RefImpl 類。
class RefImpl { constructor(value, __v_isShallow) { ... this._value = __v_isShallow ? value : toReactive(value); } get value() { trackRefValue(this); return this._value; } set value(newVal) { newVal = this.__v_isShallow ? newVal : toRaw(newVal); if (hasChanged(newVal, this._rawValue)) { this._rawValue = newVal; this._value = this.__v_isShallow ? newVal : toReactive(newVal); triggerRefValue(this, newVal); } } }
__v_isShallow
參數(shù)在這里默認(rèn)是 false,這里也順帶講一嘴,當(dāng)我們?cè)谑褂?shallowRef
時(shí),這個(gè)參數(shù)為 true。
function shallowRef(value) { return createRef(value, true); }
Ref 與 Reactive 創(chuàng)建的都是遞歸響應(yīng)的,將每一層的 json 數(shù)據(jù)解析成一個(gè) proxy 對(duì)象,shallowRef 與 shallowReactive 創(chuàng)建的是非遞歸的響應(yīng)對(duì)象,shallowReactive 創(chuàng)建的數(shù)據(jù)第一層數(shù)據(jù)改變會(huì)重新渲染 dom。
var state = shallowReactive({ a:'a', gf:{ b:'b', f:{ c:'c', s:{d:'d'} } } }); // 改變第一層的數(shù)據(jù)會(huì)導(dǎo)致頁(yè)面重新渲染 state.a = '1' // 如果不改變第一層,只改變其他的數(shù)據(jù)頁(yè)面不會(huì)重新渲染 state.gf.b = 2
通過(guò) shallowRef 創(chuàng)建的響應(yīng)式對(duì)象,需要修改整個(gè) value 才能重新渲染 dom。
var state = shallowRef({ a:'a', gf:{ b:'b', f:{ c:'c', s:{d:'d'} } } }); // 不會(huì)重新渲染 state.value.a = 1 // 要修改整個(gè) value 才能重新渲染 state.value = { a:'1', gf:{ b:'2', f:{ c:'3', s:{d:'d'} } } }
如果想更新 shallowRef 的某一層數(shù)據(jù),并且想觸發(fā)渲染,可以使用 triggerRef。
var state = shallowRef({ a:'a', gf:{ b:'b', f:{ c:'c', s:{d:'d'} } } }) state.value.gf.f.s.d = 4 triggerRef(state)
所以這里會(huì)走到 toReactive(value)
函數(shù)。
const isObject = (val) => val !== null && typeof val === 'object'; const toReactive = (value) => isObject(value) ? reactive(value) : value;
可以看到,如果傳入的參數(shù)是一個(gè)對(duì)象的話,返回值將會(huì)繼續(xù)調(diào)用 reactive 方法來(lái)進(jìn)行包裹,reactive 最終會(huì)通過(guò) Proxy 來(lái)進(jìn)行實(shí)現(xiàn)響應(yīng)攔截,返回的也是一個(gè) Proxy 對(duì)象,但在這里不重要,我們只需要知道當(dāng) ref 的參數(shù)為對(duì)象時(shí),用的就是 reactive 方法。
const data = reactive({ count: 1, }); console.log(data); const data_ref = ref({ count: 1, }); console.log(data_ref);
結(jié)果顯然,讓對(duì) ref 傳入對(duì)象作為參數(shù)時(shí)和傳入基本類型作為參數(shù)返回結(jié)果情況是不一樣的。
基本類型返回值value
就是具體的值,對(duì)象類型返回值value
是 reactive 方法創(chuàng)建的 proxy 對(duì)象。
通過(guò)源碼來(lái)看,其實(shí)也證明了,在 Vue3 中,如果是把對(duì)象類型的數(shù)據(jù)弄成響應(yīng)式,reactive 和 ref 都可以,且ref 內(nèi)部是通過(guò)r eactive 來(lái)支持的。
也就是說(shuō),你 reactive 能做的,我 ref 也能做。
ref 能做,但是 reactive 不能做
其實(shí)通過(guò)上面的例子就能知道有什么是 reactive 不能做的呢?很明顯,reactive 不支持對(duì)基本類型數(shù)據(jù)響應(yīng)式,也就是說(shuō)基本類型數(shù)據(jù)不能直接作為 reactive 的參數(shù)來(lái)使用。
簡(jiǎn)單看看源碼。
function reactive(target) { ... return createReactiveObject(...); }
reactive 函數(shù)跳轉(zhuǎn)到 createReactiveObject 函數(shù)。
const isObject = (val) => val !== null && typeof val === 'object'; function createReactiveObject(...) { if (!isObject(target)) { { console.warn(`value cannot be made reactive: ${String(target)}`); } return target; } ... const proxy = new Proxy(...); proxyMap.set(target, proxy); return proxy; }
createReactiveObject 一開(kāi)始就會(huì)判斷 target
是否是對(duì)象,如果不是對(duì)象就會(huì)直接??提示返回。如果是對(duì)象就會(huì)把 target 用 Proxy 變成響應(yīng)式對(duì)象。
const data = reactive(10);
總結(jié)
我們通過(guò)源碼來(lái)分析了兩個(gè)響應(yīng)式 API,發(fā)現(xiàn) Vue3 中有沒(méi)有 reactive 能做而 ref 做不了的場(chǎng)景?
結(jié)論是:沒(méi)有
簡(jiǎn)單來(lái)說(shuō) ref 是在 reactive 上在進(jìn)行了封裝進(jìn)行了增強(qiáng),所以在 Vue3 中 reactive 能做的,ref 也能做,reactive 不能做的,ref 也能做。
參考
https://v3.cn.vuejs.org/api/refs-api.html#ref
https://v3.cn.vuejs.org/api/basic-reactivity.html
https://v3.cn.vuejs.org/guide/reactivity.html#什么是響應(yīng)性
https://github.com/vuejs/docs-next-zh-c
以上就是Vue3中reactive與ref函數(shù)使用場(chǎng)景的詳細(xì)內(nèi)容,更多關(guān)于Vue3 reactive ref函數(shù)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
詳解vue.js2.0父組件點(diǎn)擊觸發(fā)子組件方法
本篇文章主要介紹了詳解vue.js2.0父組件點(diǎn)擊觸發(fā)子組件方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-05-05Vue3 組件庫(kù)的環(huán)境配置搭建過(guò)程
這篇文章主要介紹了Vue3 組件庫(kù)的環(huán)境配置搭建過(guò)程,使用 Vite+Ts 開(kāi)發(fā)的是 Vue3 組件庫(kù),所以我們需要安裝 typescript、vue3,同時(shí)項(xiàng)目將采用 Less 進(jìn)行組件庫(kù)樣式的管理,需要的朋友可以參考下2023-03-03el-date-picker默認(rèn)結(jié)束為當(dāng)前時(shí)分秒的操作方法
在element?ui中的日期時(shí)間選擇組件中默認(rèn)是00:00,現(xiàn)在需求是點(diǎn)擊默認(rèn)結(jié)束時(shí)間為當(dāng)前時(shí)分秒,查了很多資料寫(xiě)的都不準(zhǔn)確?,今天給大家分享el-date-picker默認(rèn)結(jié)束為當(dāng)前時(shí)分秒的操作方法,感興趣的朋友一起看看吧2024-01-01Vue3集成json-editor-vue3的代碼實(shí)現(xiàn)
這篇文章主要介紹了Vue3集成json-editor-vue3的代碼實(shí)現(xiàn),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2023-11-11vue+video.js實(shí)現(xiàn)視頻播放列表
這篇文章主要為大家詳細(xì)介紹了vue+video.js實(shí)現(xiàn)視頻播放列表,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-10-10Vue實(shí)現(xiàn)計(jì)數(shù)器案例
這篇文章主要為大家詳細(xì)介紹了Vue計(jì)數(shù)器案例的實(shí)現(xiàn)方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-06-06