From 82bdf8625475e81c44f0d4db4061b882d2fe7612 Mon Sep 17 00:00:00 2001 From: Evan You Date: Fri, 15 Apr 2022 16:43:17 +0800 Subject: [PATCH] fix(reactivity): ensure computed is invalidated before other effects fix #5720 --- .../reactivity/__tests__/computed.spec.ts | 17 +++++++++ packages/reactivity/src/effect.ts | 35 +++++++++++++------ 2 files changed, 42 insertions(+), 10 deletions(-) diff --git a/packages/reactivity/__tests__/computed.spec.ts b/packages/reactivity/__tests__/computed.spec.ts index a3efc8c8..3e4dead8 100644 --- a/packages/reactivity/__tests__/computed.spec.ts +++ b/packages/reactivity/__tests__/computed.spec.ts @@ -170,6 +170,23 @@ describe('reactivity/computed', () => { expect(dummy).toBe(-1) }) + // #5720 + it('should invalidate before non-computed effects', () => { + let plusOneValues: number[] = [] + const n = ref(0) + const plusOne = computed(() => n.value + 1) + effect(() => { + n.value + plusOneValues.push(plusOne.value) + }) + // access plusOne, causing it to be non-dirty + plusOne.value + // mutate n + n.value++ + // on the 2nd run, plusOne.value should have already updated. + expect(plusOneValues).toMatchObject([1, 2, 2]) + }) + it('should warn if trying to set a readonly computed', () => { const n = ref(1) const plusOne = computed(() => n.value + 1) diff --git a/packages/reactivity/src/effect.ts b/packages/reactivity/src/effect.ts index 77312eaa..34b53eb8 100644 --- a/packages/reactivity/src/effect.ts +++ b/packages/reactivity/src/effect.ts @@ -348,16 +348,31 @@ export function triggerEffects( debuggerEventExtraInfo?: DebuggerEventExtraInfo ) { // spread into array for stabilization - for (const effect of isArray(dep) ? dep : [...dep]) { - if (effect !== activeEffect || effect.allowRecurse) { - if (__DEV__ && effect.onTrigger) { - effect.onTrigger(extend({ effect }, debuggerEventExtraInfo)) - } - if (effect.scheduler) { - effect.scheduler() - } else { - effect.run() - } + const effects = isArray(dep) ? dep : [...dep] + for (const effect of effects) { + if (effect.computed) { + triggerEffect(effect, debuggerEventExtraInfo) + } + } + for (const effect of effects) { + if (!effect.computed) { + triggerEffect(effect, debuggerEventExtraInfo) + } + } +} + +function triggerEffect( + effect: ReactiveEffect, + debuggerEventExtraInfo?: DebuggerEventExtraInfo +) { + if (effect !== activeEffect || effect.allowRecurse) { + if (__DEV__ && effect.onTrigger) { + effect.onTrigger(extend({ effect }, debuggerEventExtraInfo)) + } + if (effect.scheduler) { + effect.scheduler() + } else { + effect.run() } } }