diff --git a/packages/runtime-core/src/component.ts b/packages/runtime-core/src/component.ts index a658f83db5b..f2ca0464142 100644 --- a/packages/runtime-core/src/component.ts +++ b/packages/runtime-core/src/component.ts @@ -223,7 +223,7 @@ export type Component< export type { ComponentOptions } -type LifecycleHook = TFn[] | null +export type LifecycleHook = (TFn & SchedulerJob)[] | null // use `E extends any` to force evaluating type to fix #2362 export type SetupContext< diff --git a/packages/runtime-core/src/components/KeepAlive.ts b/packages/runtime-core/src/components/KeepAlive.ts index c90b9565f7c..d704d6aa7ee 100644 --- a/packages/runtime-core/src/components/KeepAlive.ts +++ b/packages/runtime-core/src/components/KeepAlive.ts @@ -38,6 +38,7 @@ import { type RendererElement, type RendererInternals, type RendererNode, + invalidateMount, queuePostRenderEffect, } from '../renderer' import { setTransitionHooks } from './BaseTransition' @@ -46,7 +47,6 @@ import { devtoolsComponentAdded } from '../devtools' import { isAsyncWrapper } from '../apiAsyncComponent' import { isSuspense } from './Suspense' import { LifecycleHooks } from '../enums' -import { invalidatePostJob } from '../scheduler' type MatchPattern = string | RegExp | (string | RegExp)[] @@ -167,10 +167,8 @@ const KeepAliveImpl: ComponentOptions = { sharedContext.deactivate = (vnode: VNode) => { const instance = vnode.component! - const { m, a } = instance - // #9264 invalidate queued lifecycle hooks - if (m) m.forEach(invalidatePostJob) - if (a) a.forEach(invalidatePostJob) + invalidateMount(instance.m) + invalidateMount(instance.a) move(vnode, storageContainer, null, MoveType.LEAVE, parentSuspense) queuePostRenderEffect(() => { diff --git a/packages/runtime-core/src/renderer.ts b/packages/runtime-core/src/renderer.ts index 059214d11cc..42f4ac5360a 100644 --- a/packages/runtime-core/src/renderer.ts +++ b/packages/runtime-core/src/renderer.ts @@ -17,6 +17,7 @@ import { type ComponentInternalInstance, type ComponentOptions, type Data, + type LifecycleHook, createComponentInstance, setupComponent, } from './component' @@ -42,7 +43,6 @@ import { flushPostFlushCbs, flushPreFlushCbs, invalidateJob, - invalidatePostJob, queueJob, queuePostFlushCb, } from './scheduler' @@ -2268,10 +2268,8 @@ function baseCreateRenderer( } const { bum, scope, update, subTree, um, m, a } = instance - - // #9264 invalidate queued lifecycle hooks - if (m) m.forEach(invalidatePostJob) - if (a) a.forEach(invalidatePostJob) + invalidateMount(m) + invalidateMount(a) // beforeUnmount hook if (bum) { @@ -2538,3 +2536,9 @@ function locateNonHydratedAsyncRoot( } } } + +export function invalidateMount(hooks: LifecycleHook) { + if (hooks) { + for (let i = 0; i < hooks.length; i++) hooks[i].active = false + } +} diff --git a/packages/runtime-core/src/scheduler.ts b/packages/runtime-core/src/scheduler.ts index e77a853b040..4ae1c6d46e7 100644 --- a/packages/runtime-core/src/scheduler.ts +++ b/packages/runtime-core/src/scheduler.ts @@ -117,16 +117,6 @@ export function invalidateJob(job: SchedulerJob) { } } -export function invalidatePostJob(job: SchedulerJob) { - const i = pendingPostFlushCbs.indexOf(job) - // the job might be the first item in the pendingPostFlushCbs. - // so index should from -1 if not in flushing - const index = activePostFlushCbs ? postFlushIndex : -1 - if (i > index) { - pendingPostFlushCbs.splice(i, 1) - } -} - export function queuePostFlushCb(cb: SchedulerJobs) { if (!isArray(cb)) { if ( @@ -195,13 +185,11 @@ export function flushPostFlushCbs(seen?: CountMap) { postFlushIndex < activePostFlushCbs.length; postFlushIndex++ ) { - if ( - __DEV__ && - checkRecursiveUpdates(seen!, activePostFlushCbs[postFlushIndex]) - ) { + const cb = activePostFlushCbs[postFlushIndex] + if (__DEV__ && checkRecursiveUpdates(seen!, cb)) { continue } - activePostFlushCbs[postFlushIndex]() + if (cb.active !== false) cb() } activePostFlushCbs = null postFlushIndex = 0