Bläddra i källkod

fix(reactivity): ensure multiple effectScope `on()` and `off()` calls maintains correct active scope (#12641)

edison 1 år sedan
förälder
incheckning
679cbdf480

+ 13 - 0
packages/reactivity/__tests__/effectScope.spec.ts

@@ -296,6 +296,19 @@ describe('reactivity/effect/scope', () => {
     })
   })
 
+  it('calling on() and off() multiple times inside an active scope should not break currentScope', () => {
+    const parentScope = effectScope()
+    parentScope.run(() => {
+      const childScope = effectScope(true)
+      childScope.on()
+      childScope.on()
+      childScope.off()
+      childScope.off()
+      childScope.off()
+      expect(getCurrentScope()).toBe(parentScope)
+    })
+  })
+
   it('should pause/resume EffectScope', async () => {
     const counter = reactive({ num: 0 })
     const fnSpy = vi.fn(() => counter.num)

+ 12 - 3
packages/reactivity/src/effectScope.ts

@@ -8,6 +8,10 @@ export class EffectScope {
    * @internal
    */
   private _active = true
+  /**
+   * @internal track `on` calls, allow `on` call multiple times
+   */
+  private _on = 0
   /**
    * @internal
    */
@@ -105,8 +109,10 @@ export class EffectScope {
    * @internal
    */
   on(): void {
-    this.prevScope = activeEffectScope
-    activeEffectScope = this
+    if (++this._on === 1) {
+      this.prevScope = activeEffectScope
+      activeEffectScope = this
+    }
   }
 
   /**
@@ -114,7 +120,10 @@ export class EffectScope {
    * @internal
    */
   off(): void {
-    activeEffectScope = this.prevScope
+    if (this._on > 0 && --this._on === 0) {
+      activeEffectScope = this.prevScope
+      this.prevScope = undefined
+    }
   }
 
   stop(fromParent?: boolean): void {