diff --git a/packages/runtime-core/__tests__/apiWatch.spec.ts b/packages/runtime-core/__tests__/apiWatch.spec.ts index 7d2a1e73c08..40b45922375 100644 --- a/packages/runtime-core/__tests__/apiWatch.spec.ts +++ b/packages/runtime-core/__tests__/apiWatch.spec.ts @@ -6,6 +6,7 @@ import { getCurrentInstance, nextTick, onErrorCaptured, + onScopeDispose, onWatcherCleanup, reactive, ref, @@ -1362,6 +1363,32 @@ describe('api: watch', () => { expect(source.mock.calls.some(args => args.includes(instance))) }) + test('this.$watch w/ onScopeDispose', () => { + const onCleanup = vi.fn() + const toggle = ref(true) + + const Comp = defineComponent({ + render() {}, + created(this: any) { + this.$watch( + () => 1, + function () {}, + ) + onScopeDispose(onCleanup) + }, + }) + + const App = defineComponent({ + render() { + return toggle.value ? h(Comp) : null + }, + }) + + const root = nodeOps.createElement('div') + createApp(App).mount(root) + expect(onCleanup).toBeCalledTimes(0) + }) + test('should not leak `this.proxy` to setup()', () => { const source = vi.fn() diff --git a/packages/runtime-core/src/component.ts b/packages/runtime-core/src/component.ts index 3ed42ed0b55..cf8a17e9d2b 100644 --- a/packages/runtime-core/src/component.ts +++ b/packages/runtime-core/src/component.ts @@ -760,7 +760,10 @@ if (__SSR__) { } } -export const setCurrentInstance = (instance: ComponentInternalInstance) => { +export const setCurrentInstance = ( + instance: ComponentInternalInstance, +): (() => void) => { + if (currentInstance === instance) return NOOP const prev = currentInstance internalSetCurrentInstance(instance) instance.scope.on()