Vue3中reactive丟失響應(yīng)式問(wèn)題詳解
問(wèn)題描述:
使用 reactive 定義的對(duì)象,重新賦值后失去了響應(yīng)式,改變值視圖不會(huì)發(fā)生變化。
測(cè)試代碼:
<template>
<div>
<p>{{ title }}</p>
<ul>
<li v-for="(item, index) in tableData" :key="index">{{ item }}</li>
</ul>
</div>
</template>
<script setup>
import { ref, reactive, onMounted } from 'vue'
const title = ref('我是標(biāo)題')
let tableData = reactive([1, 2, 3])
onMounted(() => {
title.value = '我是段落',
tableData = [1, 1, 1]
console.log("title=", title)
console.log("tableData=", tableData)
})
</script>輸出結(jié)果:

從上述測(cè)試代碼中,ref 定義的對(duì)象有響應(yīng)式,而 reactive 定義的對(duì)象失去了響應(yīng)式,這是什么原因呢?官網(wǎng)中寫到:
如果將一個(gè)對(duì)象賦值給 ref ,那么這個(gè)對(duì)象將通過(guò) reactive() 轉(zhuǎn)為具有深層次響應(yīng)式的對(duì)象。
那么,為什么 ref 調(diào)用 reactive 處理對(duì)象重新賦值后,不會(huì)丟失響應(yīng)式,但 reactive 卻丟失了呢?
第一步:當(dāng)我們修改 xxx.value 值的時(shí)候,setter 調(diào)用了 toReactive 方法
class RefImpl {
constructor(value, __v_isShallow) {
this.__v_isShallow = __v_isShallow;
this.dep = undefined;
this.__v_isRef = true;
this._rawValue = __v_isShallow ? value : toRaw(value);
this._value = __v_isShallow ? value : toReactive(value);
}
get value() {
trackRefValue(this);
return this._value; // get方法返回的是_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); // set方法調(diào)用 toReactive 方法
triggerRefValue(this, newVal);
}
}
}第二步:toReactive 方法判斷是否是對(duì)象,是的話就調(diào)用 reactive 方法
const toReactive = (value) => isObject(value) ? reactive(value) : value;
第三步:reactive 方法,先判斷數(shù)據(jù)是否是“只讀”的,不是就返回 createReactiveObject() 方法處理后的數(shù)據(jù)(createReactiveObject 方法將對(duì)象通過(guò) proxy 處理為響應(yīng)式對(duì)象)
function reactive(target) {
// if trying to observe a readonly proxy, return the readonly version.
if (isReadonly(target)) {
return target;
}
return createReactiveObject(target, false, mutableHandlers, mutableCollectionHandlers, reactiveMap);
}結(jié)論:
ref 定義數(shù)據(jù)(包括對(duì)象)時(shí),都會(huì)變成 RefImpl(Ref 引用對(duì)象) 類的實(shí)例,無(wú)論是修改還是重新賦值都會(huì)調(diào)用 setter,都會(huì)經(jīng)過(guò) reactive 方法處理為響應(yīng)式對(duì)象。
但是 reactive 定義數(shù)據(jù)(必須是對(duì)象),是直接調(diào)用 reactive 方法處理成響應(yīng)式對(duì)象。如果重新賦值,就會(huì)丟失原來(lái)響應(yīng)式對(duì)象的引用地址,變成一個(gè)新的引用地址,這個(gè)新的引用地址指向的對(duì)象是沒(méi)有經(jīng)過(guò) reactive 方法處理的,所以是一個(gè)普通對(duì)象,而不是響應(yīng)式對(duì)象。
如何正確使用 reactive 呢?
使用 reactive 定義數(shù)據(jù)時(shí),使用對(duì)象包含鍵值對(duì)的形式,那么就會(huì)避免重新賦值的問(wèn)題。那么,修改測(cè)試代碼為:
<template>
<div>
<p>{{ title }}</p>
<ul>
<li v-for="(item, index) in obj.tableData" :key="index">{{ item }}</li>
</ul>
</div>
</template>
<script setup>
import { ref, reactive, onMounted } from 'vue'
const title = ref('我是標(biāo)題')
let obj = reactive({
tableData: [1, 2, 3]
})
onMounted(() => {
title.value = '我是段落',
obj.tableData = [1, 1, 1]
})
</script>
總結(jié)
到此這篇關(guān)于Vue3中reactive丟失響應(yīng)式問(wèn)題的文章就介紹到這了,更多相關(guān)Vue3 reactive丟失響應(yīng)式內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
VUEJS 2.0 子組件訪問(wèn)/調(diào)用父組件的實(shí)例
下面小編就為大家分享一篇VUEJS 2.0 子組件訪問(wèn)/調(diào)用父組件的實(shí)例。具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-02-02
Vue通過(guò)axios發(fā)送ajax請(qǐng)求基礎(chǔ)演示
這篇文章主要介紹了Vue通過(guò)axios發(fā)送ajax請(qǐng)求基礎(chǔ)演示,包括了axios發(fā)送簡(jiǎn)單get請(qǐng)求,axios get傳參,axios發(fā)送post請(qǐng)求等基礎(chǔ)代碼演示需要的朋友可以參考下2023-02-02
Vue3?KeepAlive實(shí)現(xiàn)原理解析
KeepAlive?是一個(gè)內(nèi)置組件,那封裝一個(gè)組件對(duì)于大家來(lái)說(shuō)應(yīng)該不會(huì)有太大的困難,它的核心邏輯在于它的?render?函數(shù),它用?map?去記錄要緩存的組件,就是?[key,vnode]?的形式,這篇文章主要介紹了Vue3?KeepAlive實(shí)現(xiàn)原理,需要的朋友可以參考下2022-09-09
vue如何將字符串的一部分處理為html文檔并渲染到頁(yè)面
這篇文章主要介紹了vue如何將字符串的一部分處理為html文檔并渲染到頁(yè)面,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-06-06
vue-resource調(diào)用promise取數(shù)據(jù)方式詳解
這篇文章主要介紹了vue-resource調(diào)用promise取數(shù)據(jù)方式詳解,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-07-07
elementUI select組件使用及注意事項(xiàng)詳解
這篇文章主要介紹了elementUI select組件使用及注意事項(xiàng)詳解,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2019-05-05

