From 21932840eae72ffcd357a62ec596aaecc7ec224a Mon Sep 17 00:00:00 2001 From: Evan You Date: Thu, 14 Nov 2024 14:12:41 +0800 Subject: [PATCH] fix(reactiivty): avoid unnecessary watcher effect removal from inactive scope close #5783 close #5806 --- .../reactivity/__tests__/effectScope.spec.ts | 37 +++++++++++++++++++ packages/reactivity/src/effectScope.ts | 2 +- packages/reactivity/src/watch.ts | 2 +- 3 files changed, 39 insertions(+), 2 deletions(-) diff --git a/packages/reactivity/__tests__/effectScope.spec.ts b/packages/reactivity/__tests__/effectScope.spec.ts index 8a95f3252ab..537cac64c6b 100644 --- a/packages/reactivity/__tests__/effectScope.spec.ts +++ b/packages/reactivity/__tests__/effectScope.spec.ts @@ -322,4 +322,41 @@ describe('reactivity/effect/scope', () => { scope.resume() expect(fnSpy).toHaveBeenCalledTimes(3) }) + + test('removing a watcher while stopping its effectScope', async () => { + const count = ref(0) + const scope = effectScope() + let watcherCalls = 0 + let cleanupCalls = 0 + + scope.run(() => { + const stop1 = watch(count, () => { + watcherCalls++ + }) + watch(count, (val, old, onCleanup) => { + watcherCalls++ + onCleanup(() => { + cleanupCalls++ + stop1() + }) + }) + watch(count, () => { + watcherCalls++ + }) + }) + + expect(watcherCalls).toBe(0) + expect(cleanupCalls).toBe(0) + + count.value++ + await nextTick() + expect(watcherCalls).toBe(3) + expect(cleanupCalls).toBe(0) + + scope.stop() + count.value++ + await nextTick() + expect(watcherCalls).toBe(3) + expect(cleanupCalls).toBe(1) + }) }) diff --git a/packages/reactivity/src/effectScope.ts b/packages/reactivity/src/effectScope.ts index 4fa9686083c..98e45fb5707 100644 --- a/packages/reactivity/src/effectScope.ts +++ b/packages/reactivity/src/effectScope.ts @@ -117,6 +117,7 @@ export class EffectScope { stop(fromParent?: boolean): void { if (this._active) { + this._active = false let i, l for (i = 0, l = this.effects.length; i < l; i++) { this.effects[i].stop() @@ -139,7 +140,6 @@ export class EffectScope { } } this.parent = undefined - this._active = false } } } diff --git a/packages/reactivity/src/watch.ts b/packages/reactivity/src/watch.ts index 073bf88b93f..659121ca34b 100644 --- a/packages/reactivity/src/watch.ts +++ b/packages/reactivity/src/watch.ts @@ -213,7 +213,7 @@ export function watch( const scope = getCurrentScope() const watchHandle: WatchHandle = () => { effect.stop() - if (scope) { + if (scope && scope.active) { remove(scope.effects, effect) } }