Vue3中监视reactive定义的响应式数据时oldValue无法正确获取的问题

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

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所定义的一个响应式数据

当我们只是监视由ref定义的基本数据类型的时候,是可以监视到数据的新旧变化

watch(sum,(newValue,oldValue)=> {
                console.log('sum变了',newValue,oldValue);
            },{immediate:true})

由于我们配置了immediate:true,所以一上来就会先监听一次
在这里插入图片描述
控制台结果如下:

在这里插入图片描述

二、监视ref所定义的多个响应式数据

watch([sum,msg],(newValue,oldValue)=> {
                console.log('sum或msg变了',newValue,oldValue)
            },{immediate:true})

在这里插入图片描述
我们可以看到newValue 和 oldValue 的变化

在这里插入图片描述

三、监视reactive所定义的一个响应式数据的全部属性

 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

四、 监视reactive所定义的一个响应式数据中的某个属性

  watch(()=>person.name,(newValue,oldValue)=> {
                console.log('person的name变化了',newValue,oldValue)
            })

这个时候我们发现oldValue又是能正确的获得到,我们再来看看情况五

在这里插入图片描述

五、 监视reactive所定义的一个响应式数据中的某些属性

 watch([()=>person.name,()=>person.age],(newValue,oldValue)=> {
                console.log('person的name或age变化了',newValue,oldValue)
                console.log(newValue === oldValue); // false
            })

到这里oldValue也是正确的,此时小编若有所思,是不是只要监视的是某个对象的属性(前提是这个属性不能是对象),oldVlalue就是正常的,我们接着看情况六
在这里插入图片描述

六、 监视reactive所定义的一个响应式数据中的某个属性(这个属性是一个对象)

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的响应式字符串,之后监听这个字符串,将解包后的旧值新值转为对象形式即可

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
好的,我会尽力回答你的问题。首先,我们需要了解Vue3的响应式系统是如何工作的。Vue3使用了一个名为`Reactive`的函数来实现响应式。 `Reactive`函数的作用是将一个普通的JavaScript对象转换成响应式的对象。当响应式对象的属性被修改,所有依赖该属性的地方都会自动更新。 下面是`Reactive`函数的实现: ```javascript function Reactive(obj) { const handlers = { get(target, prop, receiver) { const value = Reflect.get(target, prop, receiver); track(target, prop); return isObject(value) ? Reactive(value) : value; }, set(target, prop, value, receiver) { const oldValue = Reflect.get(target, prop, receiver); let result = true; if (oldValue !== value) { result = Reflect.set(target, prop, value, receiver); trigger(target, prop); } return result; }, deleteProperty(target, prop) { const result = Reflect.deleteProperty(target, prop); trigger(target, prop); return result; } }; return new Proxy(obj, handlers); } ``` `Reactive`函数接受一个普通的JavaScript对象作为参数,返回一个响应式的对象。在实现,我们使用了ES6的Proxy对象来实现响应式。 在`get`处理器,我们使用了`track`函数来收集依赖。`track`函数的作用是将当前正在执行的计算函数添加到依赖列表。 在`set`处理器,我们首先获取旧值,然后判断新值是否与旧值相同。如果不同,我们使用`trigger`函数来触发更新。`trigger`函数的作用是遍历依赖列表,执行所有计算函数。 在`deleteProperty`处理器,我们使用`trigger`函数来触发更新,因为删除属性也可能导致依赖更新。 在以上代码,我们还使用了`isObject`函数来判断一个值是否为对象。该函数的实现如下: ```javascript function isObject(value) { return typeof value === 'object' && value !== null; } ``` 这个函数非常简单,它只是判断一个值是否为对象。如果是对象,我们就递归调用`Reactive`函数来将该对象转换成响应式。 总之,这就是Vue3的响应式系统的实现原理。通过`Reactive`函数和Proxy对象,我们可以将一个普通的JavaScript对象转换成响应式的对象,并实现自动更新。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

bin_123ge

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值