diff --git a/packages/runtime-core/__tests__/components/BaseTransition.spec.ts b/packages/runtime-core/__tests__/components/BaseTransition.spec.ts index 3184c9c9c6a..1923d161897 100644 --- a/packages/runtime-core/__tests__/components/BaseTransition.spec.ts +++ b/packages/runtime-core/__tests__/components/BaseTransition.spec.ts @@ -1230,4 +1230,9 @@ describe('BaseTransition', () => { await runTestWithKeepAlive(testInOutBeforeFinish) }) }) + + // #10719 + test('should not error on KeepAlive w/ function children', () => { + expect(() => mount({}, () => () => h('div'), true)).not.toThrow() + }) }) diff --git a/packages/runtime-core/src/components/BaseTransition.ts b/packages/runtime-core/src/components/BaseTransition.ts index e99fe0e496c..5d41751285b 100644 --- a/packages/runtime-core/src/components/BaseTransition.ts +++ b/packages/runtime-core/src/components/BaseTransition.ts @@ -16,7 +16,7 @@ import { warn } from '../warning' import { isKeepAlive } from './KeepAlive' import { toRaw } from '@vue/reactivity' import { ErrorCodes, callWithAsyncErrorHandling } from '../errorHandling' -import { PatchFlags, ShapeFlags, isArray } from '@vue/shared' +import { PatchFlags, ShapeFlags, isArray, isFunction } from '@vue/shared' import { onBeforeUnmount, onMounted } from '../apiLifecycle' import type { RendererElement } from '../renderer' @@ -459,15 +459,27 @@ function emptyPlaceholder(vnode: VNode): VNode | undefined { } function getKeepAliveChild(vnode: VNode): VNode | undefined { - return isKeepAlive(vnode) - ? // #7121 ensure get the child component subtree in case - // it's been replaced during HMR - __DEV__ && vnode.component - ? vnode.component.subTree - : vnode.children - ? ((vnode.children as VNodeArrayChildren)[0] as VNode) - : undefined - : vnode + if (!isKeepAlive(vnode)) { + return vnode + } + // #7121 ensure get the child component subtree in case + // it's been replaced during HMR + if (__DEV__ && vnode.component) { + return vnode.component.subTree + } + + const { shapeFlag, children } = vnode + + if (shapeFlag & ShapeFlags.ARRAY_CHILDREN) { + return (children as VNodeArrayChildren)[0] as VNode + } + + if ( + shapeFlag & ShapeFlags.SLOTS_CHILDREN && + isFunction((children as any).default) + ) { + return (children as any).default() + } } export function setTransitionHooks(vnode: VNode, hooks: TransitionHooks) {