diff --git a/packages/runtime-core/__tests__/apiWatch.spec.ts b/packages/runtime-core/__tests__/apiWatch.spec.ts index 3656b0a64ba..fe299edbb63 100644 --- a/packages/runtime-core/__tests__/apiWatch.spec.ts +++ b/packages/runtime-core/__tests__/apiWatch.spec.ts @@ -1443,4 +1443,35 @@ describe('api: watch', () => { expect(spy1).toHaveBeenCalledTimes(1) expect(spy2).toHaveBeenCalledTimes(1) }) + + test("effect should be removed from scope's effects after it is stopped", () => { + const num = ref(0) + let unwatch: () => void + + let instance: ComponentInternalInstance + const Comp = { + setup() { + instance = getCurrentInstance()! + unwatch = watch(num, () => { + console.log(num.value) + }) + return () => null + }, + } + const root = nodeOps.createElement('div') + createApp(Comp).mount(root) + expect(instance!.scope.effects.length).toBe(2) + unwatch!() + expect(instance!.scope.effects.length).toBe(1) + + const scope = effectScope() + scope.run(() => { + unwatch = watch(num, () => { + console.log(num.value) + }) + }) + expect(scope.effects.length).toBe(1) + unwatch!() + expect(scope.effects.length).toBe(0) + }) }) diff --git a/packages/runtime-core/src/apiWatch.ts b/packages/runtime-core/src/apiWatch.ts index 7fbcc78f36f..3a2d9e46c33 100644 --- a/packages/runtime-core/src/apiWatch.ts +++ b/packages/runtime-core/src/apiWatch.ts @@ -5,6 +5,7 @@ import { ReactiveEffect, ReactiveFlags, type Ref, + getCurrentScope, isReactive, isRef, isShallow, @@ -394,10 +395,11 @@ function doWatch( const effect = new ReactiveEffect(getter, NOOP, scheduler) + const scope = getCurrentScope() const unwatch = () => { effect.stop() - if (instance && instance.scope) { - remove(instance.scope.effects!, effect) + if (scope) { + remove(scope.effects, effect) } }