diff --git a/packages/reactivity/__tests__/effectScope.spec.ts b/packages/reactivity/__tests__/effectScope.spec.ts index debbdafb1e7..84310b985f2 100644 --- a/packages/reactivity/__tests__/effectScope.spec.ts +++ b/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) diff --git a/packages/reactivity/src/effectScope.ts b/packages/reactivity/src/effectScope.ts index 80f42db6484..9ca24c08857 100644 --- a/packages/reactivity/src/effectScope.ts +++ b/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 {