fix(keep-alive): do not invoke onVnodeBeforeUnmount if is KeepAlive component (#1079)
This commit is contained in:
parent
2e0373bb7a
commit
239270c38a
@ -7,7 +7,14 @@ import {
|
|||||||
KeepAlive,
|
KeepAlive,
|
||||||
serializeInner,
|
serializeInner,
|
||||||
nextTick,
|
nextTick,
|
||||||
ComponentOptions
|
ComponentOptions,
|
||||||
|
markRaw,
|
||||||
|
inject,
|
||||||
|
defineComponent,
|
||||||
|
ComponentPublicInstance,
|
||||||
|
Ref,
|
||||||
|
cloneVNode,
|
||||||
|
provide
|
||||||
} from '@vue/runtime-test'
|
} from '@vue/runtime-test'
|
||||||
import { KeepAliveProps } from '../../src/components/KeepAlive'
|
import { KeepAliveProps } from '../../src/components/KeepAlive'
|
||||||
|
|
||||||
@ -559,4 +566,91 @@ describe('KeepAlive', () => {
|
|||||||
expect(serializeInner(root)).toBe(`1`)
|
expect(serializeInner(root)).toBe(`1`)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should not call onVnodeUnmounted', async () => {
|
||||||
|
const Foo = markRaw({
|
||||||
|
name: 'Foo',
|
||||||
|
render() {
|
||||||
|
return h('Foo')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const Bar = markRaw({
|
||||||
|
name: 'Bar',
|
||||||
|
render() {
|
||||||
|
return h('Bar')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const spyMounted = jest.fn()
|
||||||
|
const spyUnmounted = jest.fn()
|
||||||
|
|
||||||
|
const RouterView = defineComponent({
|
||||||
|
setup(_, { slots }) {
|
||||||
|
const Component = inject<Ref<ComponentPublicInstance>>('component')
|
||||||
|
const refView = ref()
|
||||||
|
|
||||||
|
let componentProps = {
|
||||||
|
ref: refView,
|
||||||
|
onVnodeMounted() {
|
||||||
|
spyMounted()
|
||||||
|
},
|
||||||
|
onVnodeUnmounted() {
|
||||||
|
spyUnmounted()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
const child: any = slots.default!({
|
||||||
|
Component: Component!.value
|
||||||
|
})[0]
|
||||||
|
|
||||||
|
const innerChild = child.children[0]
|
||||||
|
child.children[0] = cloneVNode(innerChild, componentProps)
|
||||||
|
return child
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
let toggle: () => void = () => {}
|
||||||
|
|
||||||
|
const App = defineComponent({
|
||||||
|
setup() {
|
||||||
|
const component = ref(Foo)
|
||||||
|
|
||||||
|
provide('component', component)
|
||||||
|
|
||||||
|
toggle = () => {
|
||||||
|
component.value = component.value === Foo ? Bar : Foo
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
component,
|
||||||
|
toggle
|
||||||
|
}
|
||||||
|
},
|
||||||
|
render() {
|
||||||
|
return h(RouterView, null, {
|
||||||
|
default: ({ Component }: any) => h(KeepAlive, null, [h(Component)])
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
render(h(App), root)
|
||||||
|
await nextTick()
|
||||||
|
expect(spyMounted).toHaveBeenCalledTimes(1)
|
||||||
|
expect(spyUnmounted).toHaveBeenCalledTimes(0)
|
||||||
|
|
||||||
|
toggle()
|
||||||
|
await nextTick()
|
||||||
|
|
||||||
|
expect(spyMounted).toHaveBeenCalledTimes(2)
|
||||||
|
expect(spyUnmounted).toHaveBeenCalledTimes(0)
|
||||||
|
|
||||||
|
toggle()
|
||||||
|
await nextTick()
|
||||||
|
render(null, root)
|
||||||
|
await nextTick()
|
||||||
|
|
||||||
|
expect(spyMounted).toHaveBeenCalledTimes(2)
|
||||||
|
expect(spyUnmounted).toHaveBeenCalledTimes(2)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
@ -1713,6 +1713,7 @@ function baseCreateRenderer(
|
|||||||
) => {
|
) => {
|
||||||
const { props, ref, children, dynamicChildren, shapeFlag, dirs } = vnode
|
const { props, ref, children, dynamicChildren, shapeFlag, dirs } = vnode
|
||||||
const shouldInvokeDirs = shapeFlag & ShapeFlags.ELEMENT && dirs
|
const shouldInvokeDirs = shapeFlag & ShapeFlags.ELEMENT && dirs
|
||||||
|
const shouldKeepAlive = shapeFlag & ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE
|
||||||
let vnodeHook: VNodeHook | undefined | null
|
let vnodeHook: VNodeHook | undefined | null
|
||||||
|
|
||||||
// unset ref
|
// unset ref
|
||||||
@ -1720,12 +1721,12 @@ function baseCreateRenderer(
|
|||||||
setRef(ref, null, parentComponent, null)
|
setRef(ref, null, parentComponent, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((vnodeHook = props && props.onVnodeBeforeUnmount)) {
|
if ((vnodeHook = props && props.onVnodeBeforeUnmount) && !shouldKeepAlive) {
|
||||||
invokeVNodeHook(vnodeHook, parentComponent, vnode)
|
invokeVNodeHook(vnodeHook, parentComponent, vnode)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shapeFlag & ShapeFlags.COMPONENT) {
|
if (shapeFlag & ShapeFlags.COMPONENT) {
|
||||||
if (shapeFlag & ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE) {
|
if (shouldKeepAlive) {
|
||||||
;(parentComponent!.ctx as KeepAliveContext).deactivate(vnode)
|
;(parentComponent!.ctx as KeepAliveContext).deactivate(vnode)
|
||||||
} else {
|
} else {
|
||||||
unmountComponent(vnode.component!, parentSuspense, doRemove)
|
unmountComponent(vnode.component!, parentSuspense, doRemove)
|
||||||
@ -1757,7 +1758,10 @@ function baseCreateRenderer(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((vnodeHook = props && props.onVnodeUnmounted) || shouldInvokeDirs) {
|
if (
|
||||||
|
((vnodeHook = props && props.onVnodeUnmounted) || shouldInvokeDirs) &&
|
||||||
|
!shouldKeepAlive
|
||||||
|
) {
|
||||||
queuePostRenderEffect(() => {
|
queuePostRenderEffect(() => {
|
||||||
vnodeHook && invokeVNodeHook(vnodeHook, parentComponent, vnode)
|
vnodeHook && invokeVNodeHook(vnodeHook, parentComponent, vnode)
|
||||||
shouldInvokeDirs &&
|
shouldInvokeDirs &&
|
||||||
|
Loading…
Reference in New Issue
Block a user