diff --git a/packages/runtime-core/__tests__/apiAsyncComponent.spec.ts b/packages/runtime-core/__tests__/apiAsyncComponent.spec.ts index c9ab33ce..45b82923 100644 --- a/packages/runtime-core/__tests__/apiAsyncComponent.spec.ts +++ b/packages/runtime-core/__tests__/apiAsyncComponent.spec.ts @@ -802,7 +802,7 @@ describe('api: defineAsyncComponent', () => { expect(vnodeHooks.onVnodeUnmounted).toHaveBeenCalledTimes(1) }) - test('with keepalive', async () => { + test('with KeepAlive', async () => { const spy = jest.fn() let resolve: (comp: Component) => void @@ -813,9 +813,12 @@ describe('api: defineAsyncComponent', () => { }) ) + const Bar = defineAsyncComponent(() => Promise.resolve(() => 'Bar')) + + const toggle = ref(true) const root = nodeOps.createElement('div') const app = createApp({ - render: () => h(KeepAlive, [h(Foo)]) + render: () => h(KeepAlive, [toggle.value ? h(Foo) : h(Bar)]) }) app.mount(root) @@ -826,13 +829,16 @@ describe('api: defineAsyncComponent', () => { onActivated(() => { spy() }) - return () => 'resolved' + return () => 'Foo' } }) await timeout() - expect(serializeInner(root)).toBe('resolved') + expect(serializeInner(root)).toBe('Foo') expect(spy).toBeCalledTimes(1) - }) + toggle.value = false + await timeout() + expect(serializeInner(root)).toBe('Bar') + }) }) diff --git a/packages/runtime-core/src/apiAsyncComponent.ts b/packages/runtime-core/src/apiAsyncComponent.ts index 957aa0bb..c9b96607 100644 --- a/packages/runtime-core/src/apiAsyncComponent.ts +++ b/packages/runtime-core/src/apiAsyncComponent.ts @@ -6,7 +6,7 @@ import { isInSSRComponentSetup, ComponentOptions } from './component' -import { isFunction, isObject, ShapeFlags } from '@vue/shared' +import { isFunction, isObject } from '@vue/shared' import { ComponentPublicInstance } from './componentPublicInstance' import { createVNode, VNode } from './vnode' import { defineComponent } from './apiDefineComponent' @@ -211,14 +211,13 @@ export function defineAsyncComponent< function createInnerComp( comp: ConcreteComponent, - { vnode: { ref, props, children }, parent }: ComponentInternalInstance + { + vnode: { ref, props, children, shapeFlag }, + parent + }: ComponentInternalInstance ) { const vnode = createVNode(comp, props, children) // ensure inner component inherits the async wrapper's ref owner vnode.ref = ref - - if (parent && isKeepAlive(parent.vnode)) { - vnode.shapeFlag |= ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE - } return vnode } diff --git a/packages/runtime-core/src/renderer.ts b/packages/runtime-core/src/renderer.ts index bd4a03e8..8af783a2 100644 --- a/packages/runtime-core/src/renderer.ts +++ b/packages/runtime-core/src/renderer.ts @@ -1420,7 +1420,12 @@ function baseCreateRenderer( // activated hook for keep-alive roots. // #1742 activated hook must be accessed after first render // since the hook may be injected by a child keep-alive - if (initialVNode.shapeFlag & ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE) { + if ( + initialVNode.shapeFlag & ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE || + (parent && + isAsyncWrapper(parent.vnode) && + parent.vnode.shapeFlag & ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE) + ) { instance.a && queuePostRenderEffect(instance.a, parentSuspense) if ( __COMPAT__ &&