Skip to content

Commit aad376c

Browse files
committed
fix(runtime-core): unwatch should be callable during SSR
1 parent d0b513e commit aad376c

File tree

3 files changed

+56
-5
lines changed

3 files changed

+56
-5
lines changed

Diff for: packages/global.d.ts

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ declare var __ESM_BUNDLER__: boolean
99
declare var __ESM_BROWSER__: boolean
1010
declare var __CJS__: boolean
1111
declare var __SSR__: boolean
12+
declare var __VUE_SSR_SETTERS__: Array<(v: boolean) => void>
1213
declare var __COMMIT__: string
1314
declare var __VERSION__: string
1415
declare var __COMPAT__: boolean

Diff for: packages/runtime-core/__tests__/apiWatch.spec.ts

+50
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,56 @@ describe('api: watch', () => {
373373
expect(dummy).toBe(0)
374374
})
375375

376+
it('stopping the watcher (SSR)', async () => {
377+
type SetBoolean = (v: boolean) => void
378+
const setSSR = (ssr: boolean) => {
379+
__SSR__ = ssr
380+
__VUE_SSR_SETTERS__.forEach((setInSSRSetupState: SetBoolean) => {
381+
setInSSRSetupState(ssr)
382+
})
383+
}
384+
setSSR(true)
385+
386+
let dummy = 0
387+
const count = ref<number>(1)
388+
const captureValue = (value: number) => {
389+
dummy = value
390+
}
391+
const watchCallback = vi.fn(newValue => {
392+
captureValue(newValue)
393+
})
394+
const scenario = () => {
395+
const Comp = defineComponent({
396+
created() {
397+
const getter = () => this.count
398+
captureValue(getter()) // sets dummy to 1
399+
const stop = this.$watch(getter, watchCallback)
400+
stop()
401+
this.count = 2 // shouldn't trigger side effect
402+
},
403+
render() {
404+
return h('div', this.count)
405+
},
406+
setup() {
407+
return { count }
408+
},
409+
})
410+
const root = nodeOps.createElement('div')
411+
render(h(Comp), root)
412+
}
413+
414+
expect(scenario).not.toThrowError(/stop is not a function/)
415+
expect(watchCallback).not.toHaveBeenCalled()
416+
expect(dummy).toBe(1)
417+
await nextTick()
418+
count.value = 3 // shouldn't trigger side effect
419+
await nextTick()
420+
expect(watchCallback).not.toHaveBeenCalled()
421+
expect(dummy).toBe(1)
422+
423+
setSSR(false)
424+
})
425+
376426
it('stopping the watcher (with source)', async () => {
377427
const state = reactive({ count: 0 })
378428
let dummy

Diff for: packages/runtime-core/src/apiWatch.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -179,11 +179,11 @@ function doWatch(
179179
// immediately watch or watchEffect
180180
baseWatchOptions.once = true
181181
} else {
182-
return {
183-
stop: NOOP,
184-
resume: NOOP,
185-
pause: NOOP,
186-
} as WatchHandle
182+
const watchStopHandle = () => {}
183+
watchStopHandle.stop = NOOP
184+
watchStopHandle.resume = NOOP
185+
watchStopHandle.pause = NOOP
186+
return watchStopHandle
187187
}
188188
}
189189

0 commit comments

Comments
 (0)