
在 Vue3 的响应式系统中,Reflect.set被用于设置对象的属性值,从而触发依赖的更新。然而,如果在自行实现响应式逻辑时,直接返回 Reflect.set的执行结果,可能会在某些情况下导致更新异常。
问题原因
当在 set拦截器中直接返回 Reflect.set(...arguments)时,某些场景下会出现问题。例如,在 setTimeout回调中连续更新同一对象的两个属性,可能会导致其中一个属性的更新未能正确触发响应。这背后涉及依赖收集与更新触发的时机问题:
首次执行 Reflect.set时,会收集依赖,但并未立即触发更新;
紧接着再次收集依赖时,收集过程会基于对象当前属性值进行;
如果直接返回 Reflect.set的结果,此时对象的属性值可能尚未更新,导致第二次收集的依赖关系不准确,从而影响后续更新触发。
解决方案:先执行赋值,再触发更新
为了保证依赖在正确的状态下被收集,可以在执行 Reflect.set之后,先将其结果暂存,手动触发更新逻辑,再返回结果。这样能够确保在触发更新时,对象属性已处于最新状态,依赖收集也能基于正确的值进行。
示例代码:
set(target, prop, value, receiver) {
const result = Reflect.set(target, prop, value, receiver);
trigger(target, prop);
return result;
}通过这种方式,在类似 setTimeout中连续更新对象多个属性的场景下,每个属性的变更都能正确触发依赖更新,从而确保响应式系统按预期工作。