vue3.0 计算属性没有监听到对象变化(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调用了reactivereactive调用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更复杂吧?
除非代码很多 ,难得改🐶有不懂欢迎评论,一起探讨
创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!