Skip to content

Commit d11e978

Browse files
authoredNov 9, 2023
fix(hmr/transition): fix kept-alive component inside transition disappearing after hmr (#7126)
fix #7121
1 parent 40f4b77 commit d11e978

File tree

2 files changed

+74
-1
lines changed

2 files changed

+74
-1
lines changed
 

‎packages/runtime-core/__tests__/hmr.spec.ts

+69
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,75 @@ describe('hot module replacement', () => {
218218
expect(deactiveSpy).toHaveBeenCalledTimes(1)
219219
})
220220

221+
// #7121
222+
test('reload KeepAlive slot in Transition', async () => {
223+
const root = nodeOps.createElement('div')
224+
const childId = 'test-transition-keep-alive-reload'
225+
const unmountSpy = vi.fn()
226+
const mountSpy = vi.fn()
227+
const activeSpy = vi.fn()
228+
const deactiveSpy = vi.fn()
229+
230+
const Child: ComponentOptions = {
231+
__hmrId: childId,
232+
data() {
233+
return { count: 0 }
234+
},
235+
unmounted: unmountSpy,
236+
render: compileToFunction(`<div>{{ count }}</div>`)
237+
}
238+
createRecord(childId, Child)
239+
240+
const Parent: ComponentOptions = {
241+
components: { Child },
242+
data() {
243+
return { toggle: true }
244+
},
245+
render: compileToFunction(
246+
`<button @click="toggle = !toggle"></button><BaseTransition mode="out-in"><KeepAlive><Child v-if="toggle" /></KeepAlive></BaseTransition>`
247+
)
248+
}
249+
250+
render(h(Parent), root)
251+
expect(serializeInner(root)).toBe(`<button></button><div>0</div>`)
252+
253+
reload(childId, {
254+
__hmrId: childId,
255+
data() {
256+
return { count: 1 }
257+
},
258+
mounted: mountSpy,
259+
unmounted: unmountSpy,
260+
activated: activeSpy,
261+
deactivated: deactiveSpy,
262+
render: compileToFunction(`<div>{{ count }}</div>`)
263+
})
264+
await nextTick()
265+
expect(serializeInner(root)).toBe(`<button></button><div>1</div>`)
266+
expect(unmountSpy).toHaveBeenCalledTimes(1)
267+
expect(mountSpy).toHaveBeenCalledTimes(1)
268+
expect(activeSpy).toHaveBeenCalledTimes(1)
269+
expect(deactiveSpy).toHaveBeenCalledTimes(0)
270+
271+
// should not unmount when toggling
272+
triggerEvent(root.children[1] as TestElement, 'click')
273+
await nextTick()
274+
expect(serializeInner(root)).toBe(`<button></button><!---->`)
275+
expect(unmountSpy).toHaveBeenCalledTimes(1)
276+
expect(mountSpy).toHaveBeenCalledTimes(1)
277+
expect(activeSpy).toHaveBeenCalledTimes(1)
278+
expect(deactiveSpy).toHaveBeenCalledTimes(1)
279+
280+
// should not mount when toggling
281+
triggerEvent(root.children[1] as TestElement, 'click')
282+
await nextTick()
283+
expect(serializeInner(root)).toBe(`<button></button><div>1</div>`)
284+
expect(unmountSpy).toHaveBeenCalledTimes(1)
285+
expect(mountSpy).toHaveBeenCalledTimes(1)
286+
expect(activeSpy).toHaveBeenCalledTimes(2)
287+
expect(deactiveSpy).toHaveBeenCalledTimes(1)
288+
})
289+
221290
test('reload class component', async () => {
222291
const root = nodeOps.createElement('div')
223292
const childId = 'test4-child'

‎packages/runtime-core/src/components/BaseTransition.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -473,7 +473,11 @@ function emptyPlaceholder(vnode: VNode): VNode | undefined {
473473

474474
function getKeepAliveChild(vnode: VNode): VNode | undefined {
475475
return isKeepAlive(vnode)
476-
? vnode.children
476+
? // #7121 ensure get the child component subtree in case
477+
// it's been replaced during HMR
478+
__DEV__ && vnode.component
479+
? vnode.component.subTree
480+
: vnode.children
477481
? ((vnode.children as VNodeArrayChildren)[0] as VNode)
478482
: undefined
479483
: vnode

0 commit comments

Comments
 (0)
Please sign in to comment.