vue3中遇到reactive響應(yīng)式失效的問題記錄
vue3中reactive響應(yīng)式失效
情況簡述
初始化了一個reactive的空數(shù)組,之后調(diào)用接口,將接口返回的數(shù)據(jù)賦值給這個reactive,此時發(fā)現(xiàn)頁面數(shù)據(jù)并沒有更新。(場景:ele-table的dataList)
const dataList = reactive([]); const load = async () => { ? const res = await 接口函數(shù)(); //假設(shè)請求接口返回的數(shù)據(jù) ? // 方法1 失敗,直接賦值丟失了響應(yīng)性 ? // dataList = res; ? // 方法2 這樣也是失敗 ? // dataList.concat(res); };
原因
直接把一個新的數(shù)組賦值給dataList,導(dǎo)致reactive聲明的響應(yīng)式對象由dataList代理
被新的數(shù)組所替代,因為在操作代理對象的時候需要有代理對象作為前提,所以失去了響應(yīng)式
在vue3中不管是對象還是數(shù)組都不能直接將整個數(shù)據(jù)進行賦值,這樣會造成reactive定義的響應(yīng)式失效
就像對象的地址被替換,就不是原來的那個對象了
解決辦法
方法1:創(chuàng)建一個響應(yīng)式對象,對象的屬性是數(shù)組
let datalist = reactive({ ? list: [], }) let arr = [1,2,3] datalist.list = arr
方法2:使用ref函數(shù)(ref可以創(chuàng)建任意數(shù)據(jù)類型,reactive只能創(chuàng)建對象或者數(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時,我們發(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的值不會變,obj.a的值倒是一直在遞增。
我們都知道vue3是使用ES6的proxy特性來實現(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本身就是對對象進行攔截,通過new Proxy的返回值,攔截obj對象,當操作對象中的值時,會觸發(fā)set或者get。
但是對于原始值(string、number這些),就需要在外部包裹一下變成一個對象,不然沒辦法使用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 ? } ? // 使用一個對象包裹基本數(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把原始值包裝成一個對象,通過get value和set value方法來對原始值進行訪問,這樣在訪問值的時候就必須攜帶.value了。
而對于對象而言,使用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)會破壞響應(yīng)式?
解構(gòu)賦值,區(qū)分基本數(shù)據(jù)類型和引用類型的賦值,原始類型的賦值相當于按值傳遞,引用類型的值就相當于按引用傳遞。
const obj = { ? value: 1, ? obj1: { ? ? value: 1 ? } } const val = obj.value; const obj1 = obj.obj1;
上方的val雖然是obj.value的值,但是當訪問val時,已經(jīng)繞過了obj對象的get方法,也就是本文討論的失去響應(yīng)式。
而obj1在解構(gòu)出來的值是按引用傳遞的,內(nèi)部的指針依然指向obj.obj1,所以去訪問其中的內(nèi)容并不會失去響應(yīng)式。
總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
- 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 iview多張圖片大圖預(yù)覽、縮放翻轉(zhuǎn)
這篇文章主要為大家詳細介紹了vue iview多張圖片大圖預(yù)覽、縮放翻轉(zhuǎn),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2019-07-07Vue優(yōu)化:常見會導(dǎo)致內(nèi)存泄漏問題及優(yōu)化詳解
這篇文章主要介紹了Vue優(yōu)化:常見會導(dǎo)致內(nèi)存泄漏問題及優(yōu)化詳解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-08-08手把手搭建安裝基于windows的Vue.js運行環(huán)境
手把手教大家搭建安裝基于windows的Vue.js的運行環(huán)境,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-06-06