mirror of https://github.com/vuejs/core.git
fix(runtime-core): do not fire mount/activated hooks if unmounted before mounted (#9370)
close #8898 close #9264 close #9617
This commit is contained in:
parent
32262a9af5
commit
aa156ed5c4
|
@ -1,8 +1,10 @@
|
|||
import {
|
||||
KeepAlive,
|
||||
TrackOpTypes,
|
||||
h,
|
||||
nextTick,
|
||||
nodeOps,
|
||||
onActivated,
|
||||
onBeforeMount,
|
||||
onBeforeUnmount,
|
||||
onBeforeUpdate,
|
||||
|
@ -407,4 +409,60 @@ describe('api: lifecycle hooks', () => {
|
|||
await nextTick()
|
||||
expect(fn).toHaveBeenCalledTimes(4)
|
||||
})
|
||||
|
||||
it('immediately trigger unmount during rendering', async () => {
|
||||
const fn = vi.fn()
|
||||
const toggle = ref(false)
|
||||
|
||||
const Child = {
|
||||
setup() {
|
||||
onMounted(fn)
|
||||
// trigger unmount immediately
|
||||
toggle.value = false
|
||||
return () => h('div')
|
||||
},
|
||||
}
|
||||
|
||||
const Comp = {
|
||||
setup() {
|
||||
return () => (toggle.value ? [h(Child)] : null)
|
||||
},
|
||||
}
|
||||
|
||||
render(h(Comp), nodeOps.createElement('div'))
|
||||
|
||||
toggle.value = true
|
||||
await nextTick()
|
||||
expect(fn).toHaveBeenCalledTimes(0)
|
||||
})
|
||||
|
||||
it('immediately trigger unmount during rendering(with KeepAlive)', async () => {
|
||||
const mountedSpy = vi.fn()
|
||||
const activeSpy = vi.fn()
|
||||
const toggle = ref(false)
|
||||
|
||||
const Child = {
|
||||
setup() {
|
||||
onMounted(mountedSpy)
|
||||
onActivated(activeSpy)
|
||||
|
||||
// trigger unmount immediately
|
||||
toggle.value = false
|
||||
return () => h('div')
|
||||
},
|
||||
}
|
||||
|
||||
const Comp = {
|
||||
setup() {
|
||||
return () => h(KeepAlive, [toggle.value ? h(Child) : null])
|
||||
},
|
||||
}
|
||||
|
||||
render(h(Comp), nodeOps.createElement('div'))
|
||||
|
||||
toggle.value = true
|
||||
await nextTick()
|
||||
expect(mountedSpy).toHaveBeenCalledTimes(0)
|
||||
expect(activeSpy).toHaveBeenCalledTimes(0)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -31,9 +31,6 @@ export function injectHook(
|
|||
const wrappedHook =
|
||||
hook.__weh ||
|
||||
(hook.__weh = (...args: unknown[]) => {
|
||||
if (target.isUnmounted) {
|
||||
return
|
||||
}
|
||||
// disable tracking inside all lifecycle hooks
|
||||
// since they can potentially be called inside effects.
|
||||
pauseTracking()
|
||||
|
|
|
@ -223,7 +223,7 @@ export type Component<
|
|||
|
||||
export type { ComponentOptions }
|
||||
|
||||
type LifecycleHook<TFn = Function> = TFn[] | null
|
||||
export type LifecycleHook<TFn = Function> = (TFn & SchedulerJob)[] | null
|
||||
|
||||
// use `E extends any` to force evaluating type to fix #2362
|
||||
export type SetupContext<
|
||||
|
|
|
@ -38,6 +38,7 @@ import {
|
|||
type RendererElement,
|
||||
type RendererInternals,
|
||||
type RendererNode,
|
||||
invalidateMount,
|
||||
queuePostRenderEffect,
|
||||
} from '../renderer'
|
||||
import { setTransitionHooks } from './BaseTransition'
|
||||
|
@ -166,6 +167,9 @@ const KeepAliveImpl: ComponentOptions = {
|
|||
|
||||
sharedContext.deactivate = (vnode: VNode) => {
|
||||
const instance = vnode.component!
|
||||
invalidateMount(instance.m)
|
||||
invalidateMount(instance.a)
|
||||
|
||||
move(vnode, storageContainer, null, MoveType.LEAVE, parentSuspense)
|
||||
queuePostRenderEffect(() => {
|
||||
if (instance.da) {
|
||||
|
|
|
@ -17,6 +17,7 @@ import {
|
|||
type ComponentInternalInstance,
|
||||
type ComponentOptions,
|
||||
type Data,
|
||||
type LifecycleHook,
|
||||
createComponentInstance,
|
||||
setupComponent,
|
||||
} from './component'
|
||||
|
@ -2266,7 +2267,9 @@ function baseCreateRenderer(
|
|||
unregisterHMR(instance)
|
||||
}
|
||||
|
||||
const { bum, scope, update, subTree, um } = instance
|
||||
const { bum, scope, update, subTree, um, m, a } = instance
|
||||
invalidateMount(m)
|
||||
invalidateMount(a)
|
||||
|
||||
// beforeUnmount hook
|
||||
if (bum) {
|
||||
|
@ -2533,3 +2536,9 @@ function locateNonHydratedAsyncRoot(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function invalidateMount(hooks: LifecycleHook) {
|
||||
if (hooks) {
|
||||
for (let i = 0; i < hooks.length; i++) hooks[i].active = false
|
||||
}
|
||||
}
|
||||
|
|
|
@ -185,13 +185,11 @@ export function flushPostFlushCbs(seen?: CountMap) {
|
|||
postFlushIndex < activePostFlushCbs.length;
|
||||
postFlushIndex++
|
||||
) {
|
||||
if (
|
||||
__DEV__ &&
|
||||
checkRecursiveUpdates(seen!, activePostFlushCbs[postFlushIndex])
|
||||
) {
|
||||
const cb = activePostFlushCbs[postFlushIndex]
|
||||
if (__DEV__ && checkRecursiveUpdates(seen!, cb)) {
|
||||
continue
|
||||
}
|
||||
activePostFlushCbs[postFlushIndex]()
|
||||
if (cb.active !== false) cb()
|
||||
}
|
||||
activePostFlushCbs = null
|
||||
postFlushIndex = 0
|
||||
|
|
Loading…
Reference in New Issue