提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
Vue3中监视reactive定义的响应式数据时oldValue无法正确获取的问题,我们分6种情况进行说明
我们简单在setup里面写一点数据做测试
<template>
<h2>当前求和为:{{sum}}</h2>
<button @click="sum++">点我+1</button>
<hr>
<h2>当前的信息为:{{msg}}</h2>
<button @click="msg+='!'">修改信息</button>
<hr>
<h2>姓名:{{person.name}}</h2>
<h2>年龄:{{person.age}}</h2>
<h2>薪资:{{person.job.j1.salary}}K</h2>
<button @click="person.name+='~'">修改姓名</button>
<button @click="person.age++">增长年龄</button>
<button @click="person.job.j1.salary++">涨薪</button>
</template>
<script>
import {ref,reactive,watch} from 'vue'
export default {
name: 'Demo',
setup(){
//数据
let sum = ref(0)
let msg = ref('你好啊')
let person = reactive({
name:'张三',
age:18,
job:{
j1:{
salary:20
}
}
})
// 情况1 监视ref所定义的一个响应式数据
watch(sum,(newValue,oldValue)=> {
console.log('sum变了',newValue,oldValue);
},{immediate:true})
return {
sum,
msg,
person
}
}
}
</script>
提示:以下是本篇文章正文内容,下面案例可供参考
当我们只是监视由ref定义的基本数据类型的时候,是可以监视到数据的新旧变化
watch(sum,(newValue,oldValue)=> {
console.log('sum变了',newValue,oldValue);
},{immediate:true})
由于我们配置了immediate:true,所以一上来就会先监听一次
控制台结果如下:
watch([sum,msg],(newValue,oldValue)=> {
console.log('sum或msg变了',newValue,oldValue)
},{immediate:true})
watch(person,(newValue,oldValue)=> {
console.log('person变化了',newValue,oldValue)
console.log(newValue === oldValue); // true
},{deep:false})
当我们点击person的任意一个属性时
我们会发现没有办法正确的获取oldValue,并且 console.log(newValue === oldValue)打印的结果为真
这是为什么呢,是BUG还是vue3作者刻意设计的呢?我们接着看情况4
watch(()=>person.name,(newValue,oldValue)=> {
console.log('person的name变化了',newValue,oldValue)
})
这个时候我们发现oldValue又是能正确的获得到,我们再来看看情况五
watch([()=>person.name,()=>person.age],(newValue,oldValue)=> {
console.log('person的name或age变化了',newValue,oldValue)
console.log(newValue === oldValue); // false
})
到这里oldValue也是正确的,此时小编若有所思,是不是只要监视的是某个对象的属性(前提是这个属性不能是对象),oldVlalue就是正常的,我们接着看情况六
watch(()=>person.job,(newValue,oldValue)=> {
console.log('person的job变化了',newValue,oldValue)
console.log(newValue === oldValue); // true
},{deep:true}) //此处由于监视的是reactive素定义的对象中的某个属性,所以deep配置有效 */
果然只要监视的是值本身是一个对象,就没法正确获得到oldValue
小编也验证了一下如果这里监视的是person.job.j1.salary,oldValue是能正确的获取到的。
1、如果定义了reactive的数据,想去使用watch监听数据改变,则无法正确获取旧值,并且deep属性配置无效,自动强制开启了深层次监听。
2、如果使用 ref 初始化一个对象或者数组类型的数据,会被自动转成reactive的实现方式,生成proxy代理对象。也会变得无法正确取旧值。
3、用任何方式生成的数据,如果接收的变量是一个proxy代理对象,就都会导致watch这个对象时,watch回调里无法正确获取旧值。
4、本质是newvalue和oldvalue是指向同一个对象,所以才会产生2者相同的情况,我们可以通过计算属性,将响应式对象转换为ComputedRef的响应式字符串,之后监听这个字符串,将解包后的旧值新值转为对象形式即可