$attrs中的对象没有变化,但触发了watch监听?

$attrs 奇怪现象:绑定的数据没有变化,但watch触发了

假设$attrs中有个变量info
1、当info不管是基本数据类型还是引用数据类型时, 都存在以下问题: 不管这个对象改没改变,handler都执行了

// 父组件调用card
<card :info="info"></card>
data中的info: {a:1} // 为1 同样有这个问题
 
 
// 在子组件card组件中监听
watch: {
   '$attrs.info': {
   		handler(newV, oldV){
        	console.log(newV == oldV) // false , {a:1}明明没有改变,但watch认为它是个新的
       },
       deep: true,
       immediate: true,
    }
 }

导致这种情况的原因是:
是父组件的非info数据的变化导致了父组件及其子组件的更新,$attrs 是响应式数据,子组件更新导致
$attrs 被重新赋值了,即使监听的info没有变化。因为$attrs变化了,所以watch执行了。

解决方案
1、可以通过判断info的值是否一样
watch: {
   '$attrs.info': {
   		handler(newV, oldV){
	   		if (!_.isEqual(newVal, value)) {
	        	console.log('值变化才触发')
	        }
       },
       deep: true,
       immediate: true,
    }
 }
2、通过props 接收info,并对info进行监听,就不存在这个问题
info:{
   handler(newV,old) {
    console.log('info改变了,触发')
  },
  deep: true,
  immediate: true,
}
    
1、 基本数据类型
只有值改变时才触发watch
2、引用数据类型
同一个引用,内容改变,触发;
引用地址变化,触发;
watch内部的判断是:
不同的对象都不相等, 即使内部数据一样,对象(引用数据类型,如数组)只有引用地址一样才是相同的

比如:对象浅拷贝,内部数据是同一个引用
var obj1 = {
    'a':{name: 123},
    'b':{name: 45}
}
var obj2 = {...obj1}
console.log(obj1.a === obj2.a)  // true

$attrs 数据没有变化,却让子组件更新的原因

参考来源: https://www.jb51.net/article/194252.htm

大概总结一下:

在子组件有v-bind="$attrs",就会在 initRender 方法中,将 $attrs 属性绑定到了 this 上,并且设置成响应式对象。Vue 通过 Object.defineProperty 方法进行依赖收集, 我们在访问 $attrs 时,它( dep)会将 $attrs 所在的 Watcher 收集到 depsubs 里面,从而在设置时进行派发更新notify(),通知视图渲染。

$attrs的依赖收集发生在v-bind中, 通过vue-template-compiler 编译源代码即可发现。
所以当 input 中 v-model 的值更新时,触发 set 通知更新,而在更新组件时调用的 updateChildComponent 方法中会对 $attrs 进行赋值。

所以会触发 $attrsset ,导致它所在的 Watcher 进行更新,也就会导致子组件更新了。而如果没有绑定 v-bind="$attrs" ,则虽然也会到这一步,但是没有依赖收集的过程,就无法去更新子组件了。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值