vue3中遇到reactive響應(yīng)式失效的問題記錄
vue3中reactive響應(yīng)式失效
情況簡(jiǎn)述
初始化了一個(gè)reactive的空數(shù)組,之后調(diào)用接口,將接口返回的數(shù)據(jù)賦值給這個(gè)reactive,此時(shí)發(fā)現(xiàn)頁面數(shù)據(jù)并沒有更新。(場(chǎng)景:ele-table的dataList)
const dataList = reactive([]); const load = async () => { ? const res = await 接口函數(shù)(); //假設(shè)請(qǐng)求接口返回的數(shù)據(jù) ? // 方法1 失敗,直接賦值丟失了響應(yīng)性 ? // dataList = res; ? // 方法2 這樣也是失敗 ? // dataList.concat(res); };
原因
直接把一個(gè)新的數(shù)組賦值給dataList,導(dǎo)致reactive聲明的響應(yīng)式對(duì)象由dataList代理
被新的數(shù)組所替代,因?yàn)樵诓僮鞔韺?duì)象的時(shí)候需要有代理對(duì)象作為前提,所以失去了響應(yīng)式
在vue3中不管是對(duì)象還是數(shù)組都不能直接將整個(gè)數(shù)據(jù)進(jìn)行賦值,這樣會(huì)造成reactive定義的響應(yīng)式失效
就像對(duì)象的地址被替換,就不是原來的那個(gè)對(duì)象了
解決辦法
方法1:創(chuàng)建一個(gè)響應(yīng)式對(duì)象,對(duì)象的屬性是數(shù)組
let datalist = reactive({ ? list: [], }) let arr = [1,2,3] datalist.list = arr
方法2:使用ref函數(shù)(ref可以創(chuàng)建任意數(shù)據(jù)類型,reactive只能創(chuàng)建對(duì)象或者數(shù)組)
const datalist = ref([]) datalist.value = [1, 2, 3]?
方法3:數(shù)組的push
let datalist = reactive([]) let arr = [1, 2, 3] arr.forEach((item) => {? ?datalist.push(item) })?
或
let datalist = reactive([]) let arr = [1, 2, 3] datalist.push(...arr)
vue3解構(gòu)響應(yīng)式失效解析
在使用vue3時(shí),我們發(fā)現(xiàn)不能使用解構(gòu)來處理響應(yīng)式數(shù)據(jù),今天我們來看看究竟是為什么。
在vue3中解構(gòu)響應(yīng)式數(shù)據(jù)
<div>{{counter}}</div> <div>{{obj.value}}</div> const reactiveObj = reactive({ ? counter: 0, ? obj: { ? ? value: 1 ? } }); setInterval(() => { ? reactiveObj.counter++; ? reactiveObj.obj.value++; }, 1000); const { counter, obj } = reactiveObj; return { ? counter, ? obj };
在頁面上可以看到,counter的值不會(huì)變,obj.a的值倒是一直在遞增。
我們都知道vue3是使用ES6的proxy特性來實(shí)現(xiàn)響應(yīng)式的,先來回顧一下proxy。
const obj = { ? ? value: 1 } const proxy = new Proxy(obj, { ? ? get: function(target, key) { ? ? ? ? return Reflect.get(...arguments); ? ? }, ? ? set: function(target, key, value) { ? ? ? ? return Reflect.set(...arguments) ? ? } }) proxy.value++; console.log(proxy.value); ? // 2
proxy本身就是對(duì)對(duì)象進(jìn)行攔截,通過new Proxy的返回值,攔截obj對(duì)象,當(dāng)操作對(duì)象中的值時(shí),會(huì)觸發(fā)set或者get。
但是對(duì)于原始值(string、number這些),就需要在外部包裹一下變成一個(gè)對(duì)象,不然沒辦法使用new Proxy去攔截。
我們來看看vue3是如何處理的。
在vue3中,使用ref來為基本數(shù)據(jù)類型添加響應(yīng)式。
export function ref(value?: unknown) { ? return createRef(value, false) } function createRef(rawValue: unknown, shallow: boolean) { ? if (isRef(rawValue)) { ? ? return rawValue ? } ? // 使用一個(gè)對(duì)象包裹基本數(shù)據(jù)類型數(shù)據(jù) ? 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) { ? ? 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) ? ? } ? } }
從上面的代碼可以發(fā)現(xiàn),vue3把原始值包裝成一個(gè)對(duì)象,通過get value和set value方法來對(duì)原始值進(jìn)行訪問,這樣在訪問值的時(shí)候就必須攜帶.value了。
而對(duì)于對(duì)象而言,使用ref的話內(nèi)部還是調(diào)用reactive。
export const toReactive = <T extends unknown>(value: T): T => ? isObject(value) ? reactive(value) : value export function reactive(target: object) { ? if (isReadonly(target)) { ? ? return target ? } ? return createReactiveObject( ? ? target, ? ? false, ? ? mutableHandlers, ? ? mutableCollectionHandlers, ? ? reactiveMap ? ) }
但是還是需要通過.value去訪問內(nèi)部的響應(yīng)式數(shù)據(jù).
let reactiveObj = ref({ ? counter: 0, ? obj: { ? ? a: 1 ? } }); console.log(reactiveObj.value.obj.a);
為什么解構(gòu)會(huì)破壞響應(yīng)式?
解構(gòu)賦值,區(qū)分基本數(shù)據(jù)類型和引用類型的賦值,原始類型的賦值相當(dāng)于按值傳遞,引用類型的值就相當(dāng)于按引用傳遞。
const obj = { ? value: 1, ? obj1: { ? ? value: 1 ? } } const val = obj.value; const obj1 = obj.obj1;
上方的val雖然是obj.value的值,但是當(dāng)訪問val時(shí),已經(jīng)繞過了obj對(duì)象的get方法,也就是本文討論的失去響應(yīng)式。
而obj1在解構(gòu)出來的值是按引用傳遞的,內(nèi)部的指針依然指向obj.obj1,所以去訪問其中的內(nèi)容并不會(huì)失去響應(yīng)式。
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
- vue3 reactive定義的引用類型直接賦值導(dǎo)致數(shù)據(jù)失去響應(yīng)式問題
- vue3.0 Reactive數(shù)據(jù)更新頁面沒有刷新的問題
- Vue3 reactive響應(yīng)式賦值頁面不渲染的解決
- 詳解Vue3中shallowRef和shallowReactive的使用
- vue3如何定義變量及ref、reactive、toRefs特性說明
- vue3?關(guān)于reactive的重置問題及解決
- 關(guān)于vue3中的reactive賦值問題
- vue3中的reactive函數(shù)聲明數(shù)組方式
- vue3 中使用 reactive 的問題小結(jié)
相關(guān)文章
vue setInterval 定時(shí)器失效的解決方式
這篇文章主要介紹了vue setInterval 定時(shí)器失效的解決方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-07-07Vue中常用rules校驗(yàn)規(guī)則(實(shí)例代碼)
這篇文章主要介紹了Vue中常用rules校驗(yàn)規(guī)則,本文通過實(shí)例代碼個(gè)大家介紹了一些校驗(yàn)方法,需要的朋友可以參考下2019-11-11vue iview多張圖片大圖預(yù)覽、縮放翻轉(zhuǎn)
這篇文章主要為大家詳細(xì)介紹了vue iview多張圖片大圖預(yù)覽、縮放翻轉(zhuǎn),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-07-07基于element-ui表格的二次封裝實(shí)現(xiàn)
本文主要介紹了基于element-ui表格的二次封裝實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07Vue優(yōu)化:常見會(huì)導(dǎo)致內(nèi)存泄漏問題及優(yōu)化詳解
這篇文章主要介紹了Vue優(yōu)化:常見會(huì)導(dǎo)致內(nèi)存泄漏問題及優(yōu)化詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-08-08手把手搭建安裝基于windows的Vue.js運(yùn)行環(huán)境
手把手教大家搭建安裝基于windows的Vue.js的運(yùn)行環(huán)境,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-06-06