Skip to content

Commit 239270c

Browse files
authored
fix(keep-alive): do not invoke onVnodeBeforeUnmount if is KeepAlive component (#1079)
1 parent 2e0373b commit 239270c

File tree

2 files changed

+102
-4
lines changed

2 files changed

+102
-4
lines changed

packages/runtime-core/__tests__/components/KeepAlive.spec.ts

+95-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,14 @@ import {
77
KeepAlive,
88
serializeInner,
99
nextTick,
10-
ComponentOptions
10+
ComponentOptions,
11+
markRaw,
12+
inject,
13+
defineComponent,
14+
ComponentPublicInstance,
15+
Ref,
16+
cloneVNode,
17+
provide
1118
} from '@vue/runtime-test'
1219
import { KeepAliveProps } from '../../src/components/KeepAlive'
1320

@@ -559,4 +566,91 @@ describe('KeepAlive', () => {
559566
expect(serializeInner(root)).toBe(`1`)
560567
})
561568
})
569+
570+
it('should not call onVnodeUnmounted', async () => {
571+
const Foo = markRaw({
572+
name: 'Foo',
573+
render() {
574+
return h('Foo')
575+
}
576+
})
577+
const Bar = markRaw({
578+
name: 'Bar',
579+
render() {
580+
return h('Bar')
581+
}
582+
})
583+
584+
const spyMounted = jest.fn()
585+
const spyUnmounted = jest.fn()
586+
587+
const RouterView = defineComponent({
588+
setup(_, { slots }) {
589+
const Component = inject<Ref<ComponentPublicInstance>>('component')
590+
const refView = ref()
591+
592+
let componentProps = {
593+
ref: refView,
594+
onVnodeMounted() {
595+
spyMounted()
596+
},
597+
onVnodeUnmounted() {
598+
spyUnmounted()
599+
}
600+
}
601+
602+
return () => {
603+
const child: any = slots.default!({
604+
Component: Component!.value
605+
})[0]
606+
607+
const innerChild = child.children[0]
608+
child.children[0] = cloneVNode(innerChild, componentProps)
609+
return child
610+
}
611+
}
612+
})
613+
614+
let toggle: () => void = () => {}
615+
616+
const App = defineComponent({
617+
setup() {
618+
const component = ref(Foo)
619+
620+
provide('component', component)
621+
622+
toggle = () => {
623+
component.value = component.value === Foo ? Bar : Foo
624+
}
625+
return {
626+
component,
627+
toggle
628+
}
629+
},
630+
render() {
631+
return h(RouterView, null, {
632+
default: ({ Component }: any) => h(KeepAlive, null, [h(Component)])
633+
})
634+
}
635+
})
636+
637+
render(h(App), root)
638+
await nextTick()
639+
expect(spyMounted).toHaveBeenCalledTimes(1)
640+
expect(spyUnmounted).toHaveBeenCalledTimes(0)
641+
642+
toggle()
643+
await nextTick()
644+
645+
expect(spyMounted).toHaveBeenCalledTimes(2)
646+
expect(spyUnmounted).toHaveBeenCalledTimes(0)
647+
648+
toggle()
649+
await nextTick()
650+
render(null, root)
651+
await nextTick()
652+
653+
expect(spyMounted).toHaveBeenCalledTimes(2)
654+
expect(spyUnmounted).toHaveBeenCalledTimes(2)
655+
})
562656
})

packages/runtime-core/src/renderer.ts

+7-3
Original file line numberDiff line numberDiff line change
@@ -1713,19 +1713,20 @@ function baseCreateRenderer(
17131713
) => {
17141714
const { props, ref, children, dynamicChildren, shapeFlag, dirs } = vnode
17151715
const shouldInvokeDirs = shapeFlag & ShapeFlags.ELEMENT && dirs
1716+
const shouldKeepAlive = shapeFlag & ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE
17161717
let vnodeHook: VNodeHook | undefined | null
17171718

17181719
// unset ref
17191720
if (ref != null && parentComponent) {
17201721
setRef(ref, null, parentComponent, null)
17211722
}
17221723

1723-
if ((vnodeHook = props && props.onVnodeBeforeUnmount)) {
1724+
if ((vnodeHook = props && props.onVnodeBeforeUnmount) && !shouldKeepAlive) {
17241725
invokeVNodeHook(vnodeHook, parentComponent, vnode)
17251726
}
17261727

17271728
if (shapeFlag & ShapeFlags.COMPONENT) {
1728-
if (shapeFlag & ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE) {
1729+
if (shouldKeepAlive) {
17291730
;(parentComponent!.ctx as KeepAliveContext).deactivate(vnode)
17301731
} else {
17311732
unmountComponent(vnode.component!, parentSuspense, doRemove)
@@ -1757,7 +1758,10 @@ function baseCreateRenderer(
17571758
}
17581759
}
17591760

1760-
if ((vnodeHook = props && props.onVnodeUnmounted) || shouldInvokeDirs) {
1761+
if (
1762+
((vnodeHook = props && props.onVnodeUnmounted) || shouldInvokeDirs) &&
1763+
!shouldKeepAlive
1764+
) {
17611765
queuePostRenderEffect(() => {
17621766
vnodeHook && invokeVNodeHook(vnodeHook, parentComponent, vnode)
17631767
shouldInvokeDirs &&

0 commit comments

Comments
 (0)