vue3中遇到reactive響應(yīng)式失效的問題記錄
vue3中reactive響應(yīng)式失效
情況簡述
初始化了一個(gè)reactive的空數(shù)組,之后調(diào)用接口,將接口返回的數(shù)據(jù)賦值給這個(gè)reactive,此時(shí)發(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);
};原因
直接把一個(gè)新的數(shù)組賦值給dataList,導(dǎo)致reactive聲明的響應(yīng)式對象由dataList代理
被新的數(shù)組所替代,因?yàn)樵诓僮鞔韺ο蟮臅r(shí)候需要有代理對象作為前提,所以失去了響應(yīng)式
在vue3中不管是對象還是數(shù)組都不能直接將整個(gè)數(shù)據(jù)進(jìn)行賦值,這樣會造成reactive定義的響應(yīng)式失效
就像對象的地址被替換,就不是原來的那個(gè)對象了
解決辦法
方法1:創(chuàng)建一個(gè)響應(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時(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的值不會變,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); ? // 2proxy本身就是對對象進(jìn)行攔截,通過new Proxy的返回值,攔截obj對象,當(dāng)操作對象中的值時(shí),會觸發(fā)set或者get。
但是對于原始值(string、number這些),就需要在外部包裹一下變成一個(gè)對象,不然沒辦法使用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è)對象包裹基本數(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è)對象,通過get value和set value方法來對原始值進(jìn)行訪問,這樣在訪問值的時(shí)候就必須攜帶.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ù)類型和引用類型的賦值,原始類型的賦值相當(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對象的get方法,也就是本文討論的失去響應(yīng)式。
而obj1在解構(gòu)出來的值是按引用傳遞的,內(nèi)部的指針依然指向obj.obj1,所以去訪問其中的內(nèi)容并不會失去響應(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à)值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-07-07
Vue中常用rules校驗(yàn)規(guī)則(實(shí)例代碼)
這篇文章主要介紹了Vue中常用rules校驗(yàn)規(guī)則,本文通過實(shí)例代碼個(gè)大家介紹了一些校驗(yàn)方法,需要的朋友可以參考下2019-11-11
vue 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ì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07
Vue優(yōu)化:常見會導(dǎo)致內(nèi)存泄漏問題及優(yōu)化詳解
這篇文章主要介紹了Vue優(yōu)化:常見會導(dǎo)致內(nèi)存泄漏問題及優(yōu)化詳解,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-08-08
手把手搭建安裝基于windows的Vue.js運(yùn)行環(huán)境
手把手教大家搭建安裝基于windows的Vue.js的運(yùn)行環(huán)境,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-06-06

