Vue 中 computed 修改使用的属性
学习 Vue 计算属性的时候有个疑问❓, 那就是在计算属性中修改使用的属性值, 会不会因为 Vue 的响应式而造成死循环
计算属性可以理解为是一个 getter 函数, 获取新值, 但是 vue 会做一层缓存, 只有改变才会重新计算
举个栗子🌰 :
假设有个属性叫 name , 现在需要一个计算属性 newName , 但是需要在取 newName 的时候再把 name 改成初始值, 由于 name 每次修改的值都不是上一次的值都会触发响应式, 理论上写一个点击方法用来修改一次 name 的值, 处理流程应该是 name --> newName --> name --> newName --> name --> newName .... 然而事实并不会如此
首先要知道流程是什么?
修改 name 的值, 会触发响应式, 那么响应式会调用 trigger 函数, trigger 函数最终会调用 newName 里的响应式副作用( ReactiveEffect )的 scheduler , 而 scheduler 可以根据 ComputedRefImpl 查到实现为 triggerRefValue(this); 也就是调用计算属性 get value 函数, 此时就是在执行 ReactiveEffect 捕捉的 getter 函数并且将该副作用设置为活跃状态的 ReactiveEffect , 也是外面写的 newName 函数, 在这里执行 newName 就会出现对 name 赋新值触发新的 trigger
可以注意的是 trigger 的 key 为正在修改的属性名称, 也就是 name , vue 使用一个 map 通过 key 为 name 来存储 ReactiveEffect 对象
回到上面, 在 newName 中触发新的 trigger , 实际上最后执行的是 triggerEffects , 在这里会对所有的副作用进行遍历, 当然在 newName 中副作用只有一个也就是通过 name 为 key 存储的 ReactiveEffect 对象, 此时它也是活跃状态的 ReactiveEffect , 根据 triggerEffects 中 effect !== activeEffect || effect.allowRecurse 这个判断, 正在执行的 effect 不等于活跃状态的 effect 或者允许递归才会调度 scheduler , 由于当前的 effect === activeEffect, 所以不会执行 newName 的 scheduler 也就不会去执行
结果: vue 内部处理的可能出现死循环的情况, 估计以前某个版本会出现死循环, 到现在 eslint 都会提示 Unexpected side effect in "newName" computed property. 错误