Procházet zdrojové kódy

fix(runtime-core): fix edge case of KeepAlive inside Transition with slot children (#10719)

close #10708
yangxiuxiu před 2 roky
rodič
revize
e51ca61ca0

+ 5 - 0
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()
+  })
 })

+ 22 - 10
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) {