From f76aa2a7519b40636c643a3eece004fd587a88a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Fern=C3=A1ndez?= Date: Fri, 9 May 2025 07:30:33 +0000 Subject: [PATCH] refactor: don't run components in detached effectScopes --- packages/reactivity/src/effectScope.ts | 35 ++++++++++++++++++-------- packages/runtime-core/src/component.ts | 2 +- 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/packages/reactivity/src/effectScope.ts b/packages/reactivity/src/effectScope.ts index 2e741f92ffd..4eec95c29c4 100644 --- a/packages/reactivity/src/effectScope.ts +++ b/packages/reactivity/src/effectScope.ts @@ -45,16 +45,26 @@ export class EffectScope implements Subscriber { */ private index: number | undefined - constructor(public detached = false) { - this.parent = activeEffectScope - if (!detached && activeEffectScope) { + /** + * @param relationship - Defines the parent scope of the current effect scope. + * - If `true`, the scope is detached from any parent. + * - If an instance of `EffectScope`, it becomes the parent scope. + * - Defaults to `false`, indicating the effect scope is attached to the parent if it exists. + */ + constructor(relationship: EffectScope | boolean = false) { + this.parent = + relationship === true ? undefined : relationship || activeEffectScope + + if (this.parent) { this.index = - (activeEffectScope.scopes || (activeEffectScope.scopes = [])).push( - this, - ) - 1 + (this.parent.scopes || (this.parent.scopes = [])).push(this) - 1 } } + get detached(): boolean { + return !this.parent + } + get active(): boolean { return !(this.flags & EffectFlags.STOP) } @@ -153,9 +163,9 @@ export class EffectScope implements Subscriber { } // nested scope, dereference from parent to avoid memory leaks - if (!this.detached && this.parent && !fromParent) { + if (!this.detached && this.parent && this.parent.scopes && !fromParent) { // optimized O(1) removal - const last = this.parent.scopes!.pop() + const last = this.parent.scopes.pop() if (last && last !== this) { this.parent.scopes![this.index!] = last last.index = this.index! @@ -172,11 +182,14 @@ export class EffectScope implements Subscriber { * disposed together. For detailed use cases of this API, please consult its * corresponding {@link https://github.com/vuejs/rfcs/blob/master/active-rfcs/0041-reactivity-effect-scope.md | RFC}. * - * @param detached - Can be used to create a "detached" effect scope. + * @param relationship - Defines the parent scope of the current effect scope. + * - If `true`, the scope is detached from any parent. + * - If an instance of `EffectScope`, it becomes the parent scope. + * - Defaults to `false`, indicating the effect scope is attached to the parent if it exists. * @see {@link https://vuejs.org/api/reactivity-advanced.html#effectscope} */ -export function effectScope(detached?: boolean): EffectScope { - return new EffectScope(detached) +export function effectScope(relationship?: EffectScope | boolean): EffectScope { + return new EffectScope(relationship) } /** diff --git a/packages/runtime-core/src/component.ts b/packages/runtime-core/src/component.ts index 3ed42ed0b55..b776ee78784 100644 --- a/packages/runtime-core/src/component.ts +++ b/packages/runtime-core/src/component.ts @@ -623,7 +623,7 @@ export function createComponentInstance( effect: null!, update: null!, // will be set synchronously right after creation job: null!, - scope: new EffectScope(true /* detached */), + scope: parent ? new EffectScope(parent.scope) : new EffectScope(true), render: null, proxy: null, exposed: null,