vue 计算属性未重新计算 / computed 未触发 / computed 原理&源码分析

点击可打开demo
在这里插入图片描述
这里在一秒后改了数组里value属性的值在这里插入图片描述
虽然数据有更新,但打开控制台,可以发现computed函数只在初始化时执行了一次
在这里插入图片描述
按理说一秒后改变了value值,应该执行两次才对呀?
但如果computed属性这样写,明确写明展开了每一项,获取到了value属性,就能执行第二次
在这里插入图片描述
vue的文档里提到,计算属性的方法只应该有单纯的计算,不要产生其他效果,像我们上面的demo,虽然数据有更新,但console.log没打印,这里的console.log其实就算是文档里的side effects
在这里插入图片描述
为什么会有这种表现呢?

看看vue的源码吧!顺便学习一下computed是如何实现的!

这里先说整体思路
这里用了proxy,对所有响应式对象加proxy,这样就能改他们的get和set等方法,然后当读取计算属性时,执行computed里的方法,执行的时候,会读取到其依赖的响应式对象,因为之前改了他们的set方法,所以此时能知道读取的是哪个对象的什么属性,此时就能把他加到computed属性的依赖中。但依赖的值发生改变,因为用proxy改过其get方法,同时之前收集过依赖,知道这个依赖值被哪些值所依赖,就能去触发更改。
接着看实际实现
我们对变量设为响应式对象,会用ref方法,ref方法的实现中调用了toReactive在这里插入图片描述
toReactive调用了reactive在这里插入图片描述

reactive调用createReactiveObject,并把mutableHandlers传入了参数
在这里插入图片描述

createReactiveObject使用了proxy,把mutableHandlers作为proxy的handler
在这里插入图片描述

然后我们看看handler是怎么做的在这里插入图片描述
在这里插入图片描述在这里插入图片描述

在这里插入图片描述
可以看到当get时,即获取响应式对象值时,调用了track方法,这里就是在收集依赖了,当我们在computed方法获取响应式对象时,这个computed就作为了target传入去,现在看看track方法做了什么
在这里插入图片描述
这里是{target -> key -> dep}的两个map,target就是每一个响应式对象,key就是这个对象上的属性名,dep里就存放了依赖这个属性的响应式对象列表,可以看到下面trackEffects函数里,有一行dep.add(activeEffect)
在这里插入图片描述
这里的activeEffect就是当前在运行的响应式对象,就是computed计算属性,被加到dep里了。因此,在computed里用到的其他响应式对象,当computed被执行时,其他响应式对象对应属性里就会维护一个列表,列表里放的是依赖这个属性的响应式对象,依赖收集完成。
之后就是触发了
这里用proxy改了set方法,会去调用trigger函数

在这里插入图片描述
看看trigger函数如何实现在这里插入图片描述
trigger函数的target是改了值的响应式对象本身,key是更改的属性名,然后从刚刚说的{target -> key -> dep}两个map里,拿到依赖这个对象这个key的列表deps,这里还能看到如果改的是length,还会有额外操作,感兴趣的可以去看源码,在effect.ts文件。
之后就调用triggerEffects方法,参数其实就是deps,在这里插入图片描述

然后就会去调用triggerEffect(说实话,我还没看到为啥355和360行的代码要这样写),这里如果有scheduler就会去执行,这里的scheduler是构造函数的第二个参数在这里插入图片描述

能找到是在ComputedRefImpl的构造函数赋值的,这里会把dirty改为true,然后会调用triggerRefValue在这里插入图片描述
triggerRefValue有调用triggerEffects了,是不是很熟悉?没错是解决假设你的计算属性被其他计算属性所以的,就会继续triggerEffects下去在这里插入图片描述
那实际在哪里改变值呢?还记得刚刚把dirty改为true了吗?computed的实现了,get函数如果dirty为true,就会重新计算在这里插入图片描述
这样,computed就更新了。

看完源码,终于懂了!如果在计算属性里没有明确获取某个响应式对象的某个key,那改了这个key,是不会重新执行computed的,所以就会有开头demo的现象。

回到文档在这里插入图片描述

因此,如果我仍想要有side effects,又不肯换watchers,可以明确获取一下会改变的属性值。但要记住这个知识点,可能相比有side effects就用watchers更复杂吧?
除非代码很多,难得改🐶

有不懂欢迎评论,一起探讨

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
vue中的computed原理是通过定义计算属性来实现对数据的处理和监听。计算属性是一种根据已有数据计算得出的属性,它会根据依赖的数据进行自动更新。在vue中,我们可以通过computed属性来定义计算属性computed属性是一个对象,其中的每一个属性对应一个计算属性。在计算属性中,我们可以编写一个函数,该函数返回的值就是计算属性的最终值。计算属性会自动根据它所依赖的数据进行缓存,只有依赖的数据发生变化时,才会重新计算。 当计算属性所依赖的数据发生变化时,computed会自动触发重新计算,并将计算结果缓存起来。这样,当其他地方需要使用计算属性时,直接获取缓存的值,不需要每次都重新计算,从而提高了性能。 一个计算属性可以依赖多个数据,当其中任意一个数据变化时,计算属性重新计算Vue会建立计算属性与数据之间的依赖关系,并在依赖的数据发生变化时,自动通知计算属性进行重新计算。 通过computed属性,我们可以将一些复杂的数据处理逻辑封装成函数,让代码更加清晰和易读。另外,在模板中使用计算属性的值时,直接通过计算属性的名称引用即可,不需要手动调用函数。 综上所述,computed原理是通过定义计算属性实现对数据的处理和监听,它会自动根据依赖的数据进行缓存和更新。这样可以提高性能,并使数据处理的逻辑更加清晰和易读。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值