Skip to content

Commit da49c86

Browse files
committed
fix(keep-alive): fix unmounting late-included components
fix #3648 based on #3650
1 parent 20ed16f commit da49c86

File tree

2 files changed

+77
-2
lines changed

2 files changed

+77
-2
lines changed

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

+75-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,12 @@ import {
1818
defineAsyncComponent,
1919
Component,
2020
createApp,
21-
onActivated
21+
onActivated,
22+
onUnmounted,
23+
onMounted,
24+
reactive,
25+
shallowRef,
26+
onDeactivated
2227
} from '@vue/runtime-test'
2328
import { KeepAliveProps } from '../../src/components/KeepAlive'
2429

@@ -903,4 +908,73 @@ describe('KeepAlive', () => {
903908
await nextTick()
904909
expect(handler).toHaveBeenCalledWith(err, {}, 'activated hook')
905910
})
911+
912+
// #3648
913+
test('should avoid unmount later included components', async () => {
914+
const unmountedA = jest.fn()
915+
const mountedA = jest.fn()
916+
const activatedA = jest.fn()
917+
const deactivatedA = jest.fn()
918+
const unmountedB = jest.fn()
919+
const mountedB = jest.fn()
920+
921+
const A = {
922+
name: 'A',
923+
setup() {
924+
onMounted(mountedA)
925+
onUnmounted(unmountedA)
926+
onActivated(activatedA)
927+
onDeactivated(deactivatedA)
928+
return () => 'A'
929+
}
930+
}
931+
const B = {
932+
name: 'B',
933+
setup() {
934+
onMounted(mountedB)
935+
onUnmounted(unmountedB)
936+
return () => 'B'
937+
}
938+
}
939+
940+
const include = reactive<string[]>([])
941+
const current = shallowRef(A)
942+
const app = createApp({
943+
setup() {
944+
return () => {
945+
return [
946+
h(
947+
KeepAlive,
948+
{
949+
include
950+
},
951+
h(current.value)
952+
)
953+
]
954+
}
955+
}
956+
})
957+
958+
app.mount(root)
959+
960+
expect(serializeInner(root)).toBe(`A`)
961+
expect(mountedA).toHaveBeenCalledTimes(1)
962+
expect(unmountedA).toHaveBeenCalledTimes(0)
963+
expect(activatedA).toHaveBeenCalledTimes(0)
964+
expect(deactivatedA).toHaveBeenCalledTimes(0)
965+
expect(mountedB).toHaveBeenCalledTimes(0)
966+
expect(unmountedB).toHaveBeenCalledTimes(0)
967+
968+
include.push('A') // cache A
969+
await nextTick()
970+
current.value = B // toggle to B
971+
await nextTick()
972+
expect(serializeInner(root)).toBe(`B`)
973+
expect(mountedA).toHaveBeenCalledTimes(1)
974+
expect(unmountedA).toHaveBeenCalledTimes(0)
975+
expect(activatedA).toHaveBeenCalledTimes(0)
976+
expect(deactivatedA).toHaveBeenCalledTimes(1)
977+
expect(mountedB).toHaveBeenCalledTimes(1)
978+
expect(unmountedB).toHaveBeenCalledTimes(0)
979+
})
906980
})

packages/runtime-core/src/components/KeepAlive.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ import { setTransitionHooks } from './BaseTransition'
4242
import { ComponentRenderContext } from '../componentPublicInstance'
4343
import { devtoolsComponentAdded } from '../devtools'
4444
import { isAsyncWrapper } from '../apiAsyncComponent'
45+
import { isSuspense } from './Suspense'
4546

4647
type MatchPattern = string | RegExp | (string | RegExp)[]
4748

@@ -323,7 +324,7 @@ const KeepAliveImpl: ComponentOptions = {
323324
vnode.shapeFlag |= ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE
324325

325326
current = vnode
326-
return rawVNode
327+
return isSuspense(rawVNode.type) ? rawVNode : vnode
327328
}
328329
}
329330
}

0 commit comments

Comments
 (0)