Skip to content

Commit

Permalink
fix(keep-alive): fix unmounting late-included components
Browse files Browse the repository at this point in the history
fix vuejs#3648
based on vuejs#3650
  • Loading branch information
yyx990803 authored and iwusong committed May 13, 2022
1 parent 9ddff44 commit 5f66610
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 2 deletions.
76 changes: 75 additions & 1 deletion packages/runtime-core/__tests__/components/KeepAlive.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,12 @@ import {
defineAsyncComponent,
Component,
createApp,
onActivated
onActivated,
onUnmounted,
onMounted,
reactive,
shallowRef,
onDeactivated
} from '@vue/runtime-test'
import { KeepAliveProps } from '../../src/components/KeepAlive'

Expand Down Expand Up @@ -903,4 +908,73 @@ describe('KeepAlive', () => {
await nextTick()
expect(handler).toHaveBeenCalledWith(err, {}, 'activated hook')
})

// #3648
test('should avoid unmount later included components', async () => {
const unmountedA = jest.fn()
const mountedA = jest.fn()
const activatedA = jest.fn()
const deactivatedA = jest.fn()
const unmountedB = jest.fn()
const mountedB = jest.fn()

const A = {
name: 'A',
setup() {
onMounted(mountedA)
onUnmounted(unmountedA)
onActivated(activatedA)
onDeactivated(deactivatedA)
return () => 'A'
}
}
const B = {
name: 'B',
setup() {
onMounted(mountedB)
onUnmounted(unmountedB)
return () => 'B'
}
}

const include = reactive<string[]>([])
const current = shallowRef(A)
const app = createApp({
setup() {
return () => {
return [
h(
KeepAlive,
{
include
},
h(current.value)
)
]
}
}
})

app.mount(root)

expect(serializeInner(root)).toBe(`A`)
expect(mountedA).toHaveBeenCalledTimes(1)
expect(unmountedA).toHaveBeenCalledTimes(0)
expect(activatedA).toHaveBeenCalledTimes(0)
expect(deactivatedA).toHaveBeenCalledTimes(0)
expect(mountedB).toHaveBeenCalledTimes(0)
expect(unmountedB).toHaveBeenCalledTimes(0)

include.push('A') // cache A
await nextTick()
current.value = B // toggle to B
await nextTick()
expect(serializeInner(root)).toBe(`B`)
expect(mountedA).toHaveBeenCalledTimes(1)
expect(unmountedA).toHaveBeenCalledTimes(0)
expect(activatedA).toHaveBeenCalledTimes(0)
expect(deactivatedA).toHaveBeenCalledTimes(1)
expect(mountedB).toHaveBeenCalledTimes(1)
expect(unmountedB).toHaveBeenCalledTimes(0)
})
})
3 changes: 2 additions & 1 deletion packages/runtime-core/src/components/KeepAlive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import { setTransitionHooks } from './BaseTransition'
import { ComponentRenderContext } from '../componentPublicInstance'
import { devtoolsComponentAdded } from '../devtools'
import { isAsyncWrapper } from '../apiAsyncComponent'
import { isSuspense } from './Suspense'

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

Expand Down Expand Up @@ -323,7 +324,7 @@ const KeepAliveImpl: ComponentOptions = {
vnode.shapeFlag |= ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE

current = vnode
return rawVNode
return isSuspense(rawVNode.type) ? rawVNode : vnode
}
}
}
Expand Down

0 comments on commit 5f66610

Please sign in to comment.