diff --git a/packages/runtime-core/__tests__/apiWatch.spec.ts b/packages/runtime-core/__tests__/apiWatch.spec.ts index 7a800949eea..082d585b852 100644 --- a/packages/runtime-core/__tests__/apiWatch.spec.ts +++ b/packages/runtime-core/__tests__/apiWatch.spec.ts @@ -37,6 +37,7 @@ import { toRef, triggerRef, } from '@vue/reactivity' +import { renderToString } from '@vue/server-renderer' describe('api: watch', () => { it('effect', async () => { @@ -373,6 +374,43 @@ describe('api: watch', () => { expect(dummy).toBe(0) }) + it('stopping the watcher (SSR)', async () => { + let dummy = 0 + const count = ref(1) + const captureValue = (value: number) => { + dummy = value + } + const watchCallback = vi.fn(newValue => { + captureValue(newValue) + }) + const Comp = defineComponent({ + created() { + const getter = () => this.count + captureValue(getter()) // sets dummy to 1 + const stop = this.$watch(getter, watchCallback) + stop() + this.count = 2 // shouldn't trigger side effect + }, + render() { + return h('div', this.count) + }, + setup() { + return { count } + }, + }) + let html + html = await renderToString(h(Comp)) + // should not throw here + expect(html).toBe(`
2
`) + expect(watchCallback).not.toHaveBeenCalled() + expect(dummy).toBe(1) + await nextTick() + count.value = 3 // shouldn't trigger side effect + await nextTick() + expect(watchCallback).not.toHaveBeenCalled() + expect(dummy).toBe(1) + }) + it('stopping the watcher (with source)', async () => { const state = reactive({ count: 0 }) let dummy diff --git a/packages/runtime-core/src/apiWatch.ts b/packages/runtime-core/src/apiWatch.ts index a14823beb62..798b6e7261b 100644 --- a/packages/runtime-core/src/apiWatch.ts +++ b/packages/runtime-core/src/apiWatch.ts @@ -179,11 +179,11 @@ function doWatch( // immediately watch or watchEffect baseWatchOptions.once = true } else { - return { - stop: NOOP, - resume: NOOP, - pause: NOOP, - } as WatchHandle + const watchStopHandle = () => {} + watchStopHandle.stop = NOOP + watchStopHandle.resume = NOOP + watchStopHandle.pause = NOOP + return watchStopHandle } }