]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(reactiivty): avoid unnecessary watcher effect removal from inactive scope
authorEvan You <evan@vuejs.org>
Thu, 14 Nov 2024 06:12:41 +0000 (14:12 +0800)
committerEvan You <evan@vuejs.org>
Thu, 14 Nov 2024 06:12:41 +0000 (14:12 +0800)
close #5783
close #5806

packages/reactivity/__tests__/effectScope.spec.ts
packages/reactivity/src/effectScope.ts
packages/reactivity/src/watch.ts

index 8a95f3252ab1bb33fe39734d43a543f8f69ef413..537cac64c6b94b070b4c3aa805ee5d7e0fb8d10f 100644 (file)
@@ -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)
+  })
 })
index 4fa9686083c772b9e5c6ae8626201c7fc37eee94..98e45fb5707e4a733049c6f2f59487903abb950d 100644 (file)
@@ -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
     }
   }
 }
index 073bf88b93f021491177818956f910ee6759d7e0..659121ca34b9544a1b6879cc2fc6ded2cad8adf3 100644 (file)
@@ -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)
     }
   }