From 116c21d0b40ac51a31ce99bab19cadf1d47300c9 Mon Sep 17 00:00:00 2001 From: Red Huang Date: Thu, 24 Aug 2023 01:37:05 +0800 Subject: [PATCH 1/2] fix(lifecycle): scope might changed when call hook --- src/core/instance/lifecycle.ts | 10 ++++++-- .../v3/reactivity/effectScope.spec.ts | 25 +++++++++++++++++++ 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/src/core/instance/lifecycle.ts b/src/core/instance/lifecycle.ts index 94f42e27eb5..42a23440ac4 100644 --- a/src/core/instance/lifecycle.ts +++ b/src/core/instance/lifecycle.ts @@ -6,6 +6,7 @@ import { updateComponentListeners } from './events' import { resolveSlots } from './render-helpers/resolve-slots' import { toggleObserving } from '../observer/index' import { pushTarget, popTarget } from '../observer/dep' +import { getCurrentScope } from '../../v3/reactivity/effectScope' import type { Component } from 'types/component' import type { MountedComponentVNode } from 'types/vnode' @@ -398,7 +399,8 @@ export function callHook( ) { // #7573 disable dep collection when invoking lifecycle hooks pushTarget() - const prev = currentInstance + const prevInst = currentInstance + const prevScope = getCurrentScope() setContext && setCurrentInstance(vm) const handlers = vm.$options[hook] const info = `${hook} hook` @@ -410,6 +412,10 @@ export function callHook( if (vm._hasHookEvent) { vm.$emit('hook:' + hook) } - setContext && setCurrentInstance(prev) + if (setContext) { + setCurrentInstance(prevInst) + prevScope?.on() + } + popTarget() } diff --git a/test/unit/features/v3/reactivity/effectScope.spec.ts b/test/unit/features/v3/reactivity/effectScope.spec.ts index 6b837e67cdc..974be8adcfa 100644 --- a/test/unit/features/v3/reactivity/effectScope.spec.ts +++ b/test/unit/features/v3/reactivity/effectScope.spec.ts @@ -1,3 +1,4 @@ +import Vue from 'vue' import { nextTick } from 'core/util' import { watch, @@ -290,4 +291,28 @@ describe('reactivity/effectScope', () => { expect(getCurrentScope()).toBe(parentScope) }) }) + + it('test scope should not break currentScope when component call hooks', () => { + const scope = new EffectScope() + const vm = new Vue({ + template: ` +
+
+
+ `, + data() { + return { + show: false + } + } + }).$mount() + + scope.run(() => { + // call renderTriggered hook here + vm.show = true + // this effect should be collected by scope not the component scope + effect(() => {}) + }) + expect(scope.effects.length).toBe(1) + }) }) From 7a2b541f186dd9a724eda17717b0bd9831e86116 Mon Sep 17 00:00:00 2001 From: Evan You Date: Sun, 22 Oct 2023 09:41:36 +0800 Subject: [PATCH 2/2] chore: minor tweaks --- src/core/instance/lifecycle.ts | 4 ++-- test/unit/features/v3/reactivity/effectScope.spec.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/core/instance/lifecycle.ts b/src/core/instance/lifecycle.ts index 42a23440ac4..d1b5a76d990 100644 --- a/src/core/instance/lifecycle.ts +++ b/src/core/instance/lifecycle.ts @@ -6,7 +6,6 @@ import { updateComponentListeners } from './events' import { resolveSlots } from './render-helpers/resolve-slots' import { toggleObserving } from '../observer/index' import { pushTarget, popTarget } from '../observer/dep' -import { getCurrentScope } from '../../v3/reactivity/effectScope' import type { Component } from 'types/component' import type { MountedComponentVNode } from 'types/vnode' @@ -19,6 +18,7 @@ import { invokeWithErrorHandling } from '../util/index' import { currentInstance, setCurrentInstance } from 'v3/currentInstance' +import { getCurrentScope } from 'v3/reactivity/effectScope' import { syncSetupProxy } from 'v3/apiSetup' export let activeInstance: any = null @@ -414,7 +414,7 @@ export function callHook( } if (setContext) { setCurrentInstance(prevInst) - prevScope?.on() + prevScope && prevScope.on() } popTarget() diff --git a/test/unit/features/v3/reactivity/effectScope.spec.ts b/test/unit/features/v3/reactivity/effectScope.spec.ts index 974be8adcfa..78966e42e4d 100644 --- a/test/unit/features/v3/reactivity/effectScope.spec.ts +++ b/test/unit/features/v3/reactivity/effectScope.spec.ts @@ -292,7 +292,7 @@ describe('reactivity/effectScope', () => { }) }) - it('test scope should not break currentScope when component call hooks', () => { + it('scope should not break currentScope when component call hooks', () => { const scope = new EffectScope() const vm = new Vue({ template: `