From fbc0c42bcf6dea5a6ae664223fa19d4375ca39f0 Mon Sep 17 00:00:00 2001 From: yangxiuxiu <79584569+yangxiuxiu1115@users.noreply.github.com> Date: Tue, 20 Aug 2024 16:35:08 +0800 Subject: [PATCH] fix(reactivity): ensure watcher with once: true are properly removed from effect scope (#11665) --- packages/reactivity/src/watch.ts | 20 +++++++++---------- .../runtime-core/__tests__/apiWatch.spec.ts | 5 +++++ 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/packages/reactivity/src/watch.ts b/packages/reactivity/src/watch.ts index 96da5ffe5c2..9c1eea00b9b 100644 --- a/packages/reactivity/src/watch.ts +++ b/packages/reactivity/src/watch.ts @@ -206,18 +206,26 @@ export function watch( getter = () => traverse(baseGetter(), depth) } + const scope = getCurrentScope() + const watchHandle: WatchHandle = () => { + effect.stop() + if (scope) { + remove(scope.effects, effect) + } + } + if (once) { if (cb) { const _cb = cb cb = (...args) => { _cb(...args) - effect.stop() + watchHandle() } } else { const _getter = getter getter = () => { _getter() - effect.stop() + watchHandle() } } } @@ -317,14 +325,6 @@ export function watch( effect.run() } - const scope = getCurrentScope() - const watchHandle: WatchHandle = () => { - effect.stop() - if (scope) { - remove(scope.effects, effect) - } - } - watchHandle.pause = effect.pause.bind(effect) watchHandle.resume = effect.resume.bind(effect) watchHandle.stop = watchHandle diff --git a/packages/runtime-core/__tests__/apiWatch.spec.ts b/packages/runtime-core/__tests__/apiWatch.spec.ts index b1eb85f8a13..7a800949eea 100644 --- a/packages/runtime-core/__tests__/apiWatch.spec.ts +++ b/packages/runtime-core/__tests__/apiWatch.spec.ts @@ -1771,6 +1771,11 @@ describe('api: watch', () => { expect(scope.effects.length).toBe(1) unwatch!() expect(scope.effects.length).toBe(0) + + scope.run(() => { + watch(num, () => {}, { once: true, immediate: true }) + }) + expect(scope.effects.length).toBe(0) }) // simplified case of VueUse syncRef