diff --git a/packages/reactivity/src/effect.ts b/packages/reactivity/src/effect.ts index 3c21ab71..892eef10 100644 --- a/packages/reactivity/src/effect.ts +++ b/packages/reactivity/src/effect.ts @@ -45,7 +45,6 @@ export type DebuggerEventExtraInfo = { oldTarget?: Map | Set } -const effectStack: ReactiveEffect[] = [] let activeEffect: ReactiveEffect | undefined export const ITERATE_KEY = Symbol(__DEV__ ? 'iterate' : '') @@ -54,6 +53,7 @@ export const MAP_KEY_ITERATE_KEY = Symbol(__DEV__ ? 'Map key iterate' : '') export class ReactiveEffect { active = true deps: Dep[] = [] + parent: ReactiveEffect | undefined = undefined /** * Can be attached after creation @@ -74,7 +74,7 @@ export class ReactiveEffect { constructor( public fn: () => T, public scheduler: EffectScheduler | null = null, - scope?: EffectScope | null + scope?: EffectScope ) { recordEffectScope(this, scope) } @@ -83,31 +83,37 @@ export class ReactiveEffect { if (!this.active) { return this.fn() } - if (!effectStack.length || !effectStack.includes(this)) { - try { - effectStack.push((activeEffect = this)) - enableTracking() - - trackOpBit = 1 << ++effectTrackDepth - - if (effectTrackDepth <= maxMarkerBits) { - initDepMarkers(this) - } else { - cleanupEffect(this) - } - return this.fn() - } finally { - if (effectTrackDepth <= maxMarkerBits) { - finalizeDepMarkers(this) - } - - trackOpBit = 1 << --effectTrackDepth - - resetTracking() - effectStack.pop() - const n = effectStack.length - activeEffect = n > 0 ? effectStack[n - 1] : undefined + let parent: ReactiveEffect | undefined = activeEffect + let lastShouldTrack = shouldTrack + while (parent) { + if (parent === this) { + return } + parent = parent.parent + } + try { + this.parent = activeEffect + activeEffect = this + shouldTrack = true + + trackOpBit = 1 << ++effectTrackDepth + + if (effectTrackDepth <= maxMarkerBits) { + initDepMarkers(this) + } else { + cleanupEffect(this) + } + return this.fn() + } finally { + if (effectTrackDepth <= maxMarkerBits) { + finalizeDepMarkers(this) + } + + trackOpBit = 1 << --effectTrackDepth + + activeEffect = this.parent + shouldTrack = lastShouldTrack + this.parent = undefined } } @@ -214,7 +220,7 @@ export function track(target: object, type: TrackOpTypes, key: unknown) { } export function isTracking() { - return shouldTrack && activeEffect !== undefined + return shouldTrack && !!activeEffect } export function trackEffects( diff --git a/packages/reactivity/src/effectScope.ts b/packages/reactivity/src/effectScope.ts index 864443f8..7c3dbc98 100644 --- a/packages/reactivity/src/effectScope.ts +++ b/packages/reactivity/src/effectScope.ts @@ -2,7 +2,6 @@ import { ReactiveEffect } from './effect' import { warn } from './warning' let activeEffectScope: EffectScope | undefined -const effectScopeStack: EffectScope[] = [] export class EffectScope { active = true @@ -42,24 +41,29 @@ export class EffectScope { on() { if (this.active) { - effectScopeStack.push(this) activeEffectScope = this } } off() { if (this.active) { - effectScopeStack.pop() - activeEffectScope = effectScopeStack[effectScopeStack.length - 1] + activeEffectScope = this.parent } } stop(fromParent?: boolean) { if (this.active) { - this.effects.forEach(e => e.stop()) - this.cleanups.forEach(cleanup => cleanup()) + let i, l + for (i = 0, l = this.effects.length; i < l; i++) { + this.effects[i].stop() + } + for (i = 0, l = this.cleanups.length; i < l; i++) { + this.cleanups[i]() + } if (this.scopes) { - this.scopes.forEach(e => e.stop(true)) + for (i = 0, l = this.scopes.length; i < l; i++) { + this.scopes[i].stop(true) + } } // nested scope, dereference from parent to avoid memory leaks if (this.parent && !fromParent) { @@ -81,9 +85,8 @@ export function effectScope(detached?: boolean) { export function recordEffectScope( effect: ReactiveEffect, - scope?: EffectScope | null + scope: EffectScope | undefined = activeEffectScope ) { - scope = scope || activeEffectScope if (scope && scope.active) { scope.effects.push(effect) } diff --git a/packages/reactivity/src/ref.ts b/packages/reactivity/src/ref.ts index 20aa6c0a..d9ff17ac 100644 --- a/packages/reactivity/src/ref.ts +++ b/packages/reactivity/src/ref.ts @@ -59,7 +59,7 @@ export function triggerRefValue(ref: RefBase, newVal?: any) { export function isRef(r: Ref | unknown): r is Ref export function isRef(r: any): r is Ref { - return Boolean(r && r.__v_isRef === true) + return !!(r && r.__v_isRef === true) } export function ref(