Skip to content

Commit

Permalink
fix(keep-alive): invoke initial activated hook for async components
Browse files Browse the repository at this point in the history
revert #5459
fix #5095
fix #5651
  • Loading branch information
yyx990803 committed May 12, 2022
1 parent 9d815d2 commit 20ed16f
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 12 deletions.
16 changes: 11 additions & 5 deletions packages/runtime-core/__tests__/apiAsyncComponent.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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)
Expand All @@ -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')
})
})
11 changes: 5 additions & 6 deletions packages/runtime-core/src/apiAsyncComponent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down Expand Up @@ -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
}
7 changes: 6 additions & 1 deletion packages/runtime-core/src/renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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__ &&
Expand Down

0 comments on commit 20ed16f

Please sign in to comment.