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

03-01 1306阅读 0评论

点击可打开demo

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

这里在一秒后改了数组里value属性的值vue 计算属性未重新计算 / computed 未触发 / computed 原理&源码分析

虽然数据有更新,但打开控制台,可以发现computed函数只在初始化时执行了一次

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

按理说一秒后改变了value值,应该执行两次才对呀?

但如果computed属性这样写,明确写明展开了每一项,获取到了value属性,就能执行第二次

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

vue的文档里提到,计算属性的方法只应该有单纯的计算,不要产生其他效果,像我们上面的demo,虽然数据有更新,但console.log没打印,这里的console.log其实就算是文档里的side effects

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

为什么会有这种表现呢?

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

这里先说整体思路

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

toReactive调用了reactivevue 计算属性未重新计算 / computed 未触发 / computed 原理&源码分析

reactive调用createReactiveObject,并把mutableHandlers传入了参数

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

createReactiveObject使用了proxy,把mutableHandlers作为proxy的handler

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

然后我们看看handler是怎么做的vue 计算属性未重新计算 / computed 未触发 / computed 原理&源码分析

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

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

可以看到当get时,即获取响应式对象值时,调用了track方法,这里就是在收集依赖了,当我们在computed方法获取响应式对象时,这个computed就作为了target传入去,现在看看track方法做了什么

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

这里是{target -> key -> dep}的两个map,target就是每一个响应式对象,key就是这个对象上的属性名,dep里就存放了依赖这个属性的响应式对象列表,可以看到下面trackEffects函数里,有一行dep.add(activeEffect)

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

这里的activeEffect就是当前在运行的响应式对象,就是computed计算属性,被加到dep里了。因此,在computed里用到的其他响应式对象,当computed被执行时,其他响应式对象对应属性里就会维护一个列表,列表里放的是依赖这个属性的响应式对象,依赖收集完成。

之后就是触发了

这里用proxy改了set方法,会去调用trigger函数

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

看看trigger函数如何实现vue 计算属性未重新计算 / computed 未触发 / computed 原理&源码分析

trigger函数的target是改了值的响应式对象本身,key是更改的属性名,然后从刚刚说的{target -> key -> dep}两个map里,拿到依赖这个对象这个key的列表deps,这里还能看到如果改的是length,还会有额外操作,感兴趣的可以去看源码,在effect.ts文件。

之后就调用triggerEffects方法,参数其实就是deps,vue 计算属性未重新计算 / computed 未触发 / computed 原理&源码分析

然后就会去调用triggerEffect(说实话,我还没看到为啥355和360行的代码要这样写),这里如果有scheduler就会去执行,这里的scheduler是构造函数的第二个参数vue 计算属性未重新计算 / computed 未触发 / computed 原理&源码分析

能找到是在ComputedRefImpl的构造函数赋值的,这里会把dirty改为true,然后会调用triggerRefValuevue 计算属性未重新计算 / computed 未触发 / computed 原理&源码分析

triggerRefValue有调用triggerEffects了,是不是很熟悉?没错是解决假设你的计算属性被其他计算属性所以的,就会继续triggerEffects下去vue 计算属性未重新计算 / computed 未触发 / computed 原理&源码分析

那实际在哪里改变值呢?还记得刚刚把dirty改为true了吗?computed的实现了,get函数如果dirty为true,就会重新计算vue 计算属性未重新计算 / computed 未触发 / computed 原理&源码分析

这样,computed就更新了。

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

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

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

除非代码很多,难得改🐶

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


免责声明
本网站所收集的部分公开资料来源于AI生成和互联网,转载的目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。
文章版权声明:除非注明,否则均为主机测评原创文章,转载或复制请以超链接形式并注明出处。

发表评论

快捷回复: 表情:
评论列表 (暂无评论,1306人围观)

还没有评论,来说两句吧...

目录[+]