From 509fbb58048c02b488cc14f43ced33962fa7e2e7 Mon Sep 17 00:00:00 2001 From: liulinboyi <814921718@qq.com> Date: Thu, 19 May 2022 03:08:46 +0800 Subject: [PATCH] fix: + means mounted() runs too early --- packages/runtime-core/src/apiLifecycle.ts | 38 +++++++++---- .../runtime-core/src/components/KeepAlive.ts | 5 +- packages/runtime-core/src/scheduler.ts | 53 ++++++++++++++++++- 3 files changed, 84 insertions(+), 12 deletions(-) diff --git a/packages/runtime-core/src/apiLifecycle.ts b/packages/runtime-core/src/apiLifecycle.ts index ec39308eea5..aec9787cca6 100644 --- a/packages/runtime-core/src/apiLifecycle.ts +++ b/packages/runtime-core/src/apiLifecycle.ts @@ -14,18 +14,23 @@ import { DebuggerEvent, pauseTracking, resetTracking } from '@vue/reactivity' export { onActivated, onDeactivated } from './components/KeepAlive' +export type WRAPPEDHOOK = { + (hook: Function & { __weh?: WRAPPEDHOOK; _isSuspense?: boolean }): void + _isSuspense?: boolean +} + export function injectHook( type: LifecycleHooks, - hook: Function & { __weh?: Function }, + hook: Function & { __weh?: WRAPPEDHOOK; _isSuspense?: boolean }, target: ComponentInternalInstance | null = currentInstance, prepend: boolean = false -): Function | undefined { +): WRAPPEDHOOK | undefined { if (target) { const hooks = target[type] || (target[type] = []) // cache the error handling wrapper for injected hooks so the same hook // can be properly deduped by the scheduler. "__weh" stands for "with error // handling". - const wrappedHook = + const wrappedHook: WRAPPEDHOOK = hook.__weh || (hook.__weh = (...args: unknown[]) => { if (target.isUnmounted) { @@ -43,6 +48,15 @@ export function injectHook( resetTracking() return res }) + const parent = target.parent + if ( + // `` wrapped in `` + target.suspense && + parent?.type.name === 'BaseTransition' && + !parent.suspense + ) { + wrappedHook._isSuspense = true + } if (prepend) { hooks.unshift(wrappedHook) } else { @@ -63,8 +77,13 @@ export function injectHook( } } +export interface HOOK { + (e: DebuggerEvent): void + _isSuspense?: boolean +} + export const createHook = - any>(lifecycle: LifecycleHooks) => + (lifecycle: LifecycleHooks) => (hook: T, target: ComponentInternalInstance | null = currentInstance) => // post-create lifecycle registrations are noops during SSR (except for serverPrefetch) (!isInSSRComponentSetup || lifecycle === LifecycleHooks.SERVER_PREFETCH) && @@ -86,11 +105,12 @@ export const onRenderTracked = createHook( LifecycleHooks.RENDER_TRACKED ) -export type ErrorCapturedHook = ( - err: TError, - instance: ComponentPublicInstance | null, - info: string -) => boolean | void +export type ErrorCapturedHook = { + (err: TError, instance: ComponentPublicInstance | null, info: string): + | boolean + | void + _isSuspense?: boolean +} export function onErrorCaptured( hook: ErrorCapturedHook, diff --git a/packages/runtime-core/src/components/KeepAlive.ts b/packages/runtime-core/src/components/KeepAlive.ts index 4b2c7288581..dfbf80770ad 100644 --- a/packages/runtime-core/src/components/KeepAlive.ts +++ b/packages/runtime-core/src/components/KeepAlive.ts @@ -21,7 +21,8 @@ import { injectHook, onUnmounted, onMounted, - onUpdated + onUpdated, + WRAPPEDHOOK } from '../apiLifecycle' import { isString, @@ -407,7 +408,7 @@ function registerKeepAliveHook( } function injectToKeepAliveRoot( - hook: Function & { __weh?: Function }, + hook: Function & { __weh?: WRAPPEDHOOK }, type: LifecycleHooks, target: ComponentInternalInstance, keepAliveRoot: ComponentInternalInstance diff --git a/packages/runtime-core/src/scheduler.ts b/packages/runtime-core/src/scheduler.ts index 2056d80e847..05004f22616 100644 --- a/packages/runtime-core/src/scheduler.ts +++ b/packages/runtime-core/src/scheduler.ts @@ -2,6 +2,7 @@ import { ErrorCodes, callWithErrorHandling } from './errorHandling' import { isArray, NOOP } from '@vue/shared' import { ComponentInternalInstance, getComponentName } from './component' import { warn } from './warning' +import { WRAPPEDHOOK } from './apiLifecycle' export interface SchedulerJob extends Function { id?: number @@ -47,6 +48,11 @@ const pendingPostFlushCbs: SchedulerJob[] = [] let activePostFlushCbs: SchedulerJob[] | null = null let postFlushIndex = 0 +// only for Suspense when `` wrapped in `` +const pendingSuspenseFlushCbs: SchedulerJob[] = [] +let activeSuspenseFlushCbs: SchedulerJob[] | null = null +let suspenseFlushIndex = 0 + const resolvedPromise = /*#__PURE__*/ Promise.resolve() as Promise let currentFlushPromise: Promise | null = null @@ -149,6 +155,15 @@ export function queuePostFlushCb(cb: SchedulerJobs) { queueCb(cb, activePostFlushCbs, pendingPostFlushCbs, postFlushIndex) } +export function queueSuspenseFlushCb(cb: SchedulerJobs) { + queueCb( + cb, + activeSuspenseFlushCbs, + pendingSuspenseFlushCbs, + suspenseFlushIndex + ) +} + export function flushPreFlushCbs( seen?: CountMap, parentJob: SchedulerJob | null = null @@ -219,6 +234,36 @@ export function flushPostFlushCbs(seen?: CountMap) { } } +export function flushSuspenseFlushCbs(seen?: CountMap) { + if (pendingSuspenseFlushCbs.length) { + const deduped = [...new Set(pendingSuspenseFlushCbs)] + pendingSuspenseFlushCbs.length = 0 + + activeSuspenseFlushCbs = deduped + if (__DEV__) { + seen = seen || new Map() + } + + activeSuspenseFlushCbs.sort((a, b) => getId(a) - getId(b)) + + for ( + suspenseFlushIndex = 0; + suspenseFlushIndex < activeSuspenseFlushCbs.length; + suspenseFlushIndex++ + ) { + if ( + __DEV__ && + checkRecursiveUpdates(seen!, activeSuspenseFlushCbs[suspenseFlushIndex]) + ) { + continue + } + activeSuspenseFlushCbs[suspenseFlushIndex]() + } + activeSuspenseFlushCbs = null + suspenseFlushIndex = 0 + } +} + const getId = (job: SchedulerJob): number => job.id == null ? Infinity : job.id @@ -264,7 +309,13 @@ function flushJobs(seen?: CountMap) { flushIndex = 0 queue.length = 0 - flushPostFlushCbs(seen) + if (!pendingPostFlushCbs.find(n => (n as WRAPPEDHOOK)._isSuspense)) { + flushPostFlushCbs(seen) + flushSuspenseFlushCbs(seen) + } else { + queueSuspenseFlushCb(pendingPostFlushCbs) + pendingPostFlushCbs.length = 0 + } isFlushing = false currentFlushPromise = null