diff --git a/packages-private/vapor-e2e-test/__tests__/transition.spec.ts b/packages-private/vapor-e2e-test/__tests__/transition.spec.ts
index 1dce93782e1..70660c72d8f 100644
--- a/packages-private/vapor-e2e-test/__tests__/transition.spec.ts
+++ b/packages-private/vapor-e2e-test/__tests__/transition.spec.ts
@@ -922,6 +922,380 @@ describe('vapor transition', () => {
})
expect(calls).toStrictEqual(['TrueBranch'])
})
+
+ test(
+ 'switch child then update include (out-in mode)',
+ async () => {
+ const containerSelector = '.keep-alive-update-include > div'
+ const btnSwitchToB = '.keep-alive-update-include > #switchToB'
+ const btnSwitchToA = '.keep-alive-update-include > #switchToA'
+ const btnSwitchToC = '.keep-alive-update-include > #switchToC'
+
+ await transitionFinish()
+ expect(await html(containerSelector)).toBe('
CompA
')
+
+ await click(btnSwitchToB)
+ await nextTick()
+ await click(btnSwitchToC)
+ await transitionFinish()
+ await transitionFinish()
+ expect(await html(containerSelector)).toBe('CompC
')
+
+ await click(btnSwitchToA)
+ await transitionFinish()
+ await transitionFinish()
+ expect(await html(containerSelector)).toBe('CompA
')
+
+ let calls = await page().evaluate(() => {
+ return (window as any).getCalls('unmount')
+ })
+ expect(calls).toStrictEqual(['CompC unmounted'])
+
+ // Unlike vdom, CompA does not update because there are no state changes
+ // expect CompA only update once
+ // calls = await page().evaluate(() => {
+ // return (window as any).getCalls('updated')
+ // })
+ // expect(calls).toStrictEqual(['CompA updated'])
+ },
+ E2E_TIMEOUT,
+ )
+
+ // #11775
+ // test(
+ // 'switch child then update include (out-in mode)',
+ // async () => {
+ // const onUpdatedSpyA = vi.fn()
+ // const onUnmountedSpyC = vi.fn()
+
+ // await page().exposeFunction('onUpdatedSpyA', onUpdatedSpyA)
+ // await page().exposeFunction('onUnmountedSpyC', onUnmountedSpyC)
+
+ // await page().evaluate(() => {
+ // const { onUpdatedSpyA, onUnmountedSpyC } = window as any
+ // const { createApp, ref, shallowRef, h, onUpdated, onUnmounted } = (
+ // window as any
+ // ).Vue
+ // createApp({
+ // template: `
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ // `,
+ // components: {
+ // CompA: {
+ // name: 'CompA',
+ // setup() {
+ // onUpdated(onUpdatedSpyA)
+ // return () => h('div', 'CompA')
+ // },
+ // },
+ // CompB: {
+ // name: 'CompB',
+ // setup() {
+ // return () => h('div', 'CompB')
+ // },
+ // },
+ // CompC: {
+ // name: 'CompC',
+ // setup() {
+ // onUnmounted(onUnmountedSpyC)
+ // return () => h('div', 'CompC')
+ // },
+ // },
+ // },
+ // setup: () => {
+ // const includeRef = ref(['CompA', 'CompB', 'CompC'])
+ // const current = shallowRef('CompA')
+ // const switchToB = () => (current.value = 'CompB')
+ // const switchToC = () => (current.value = 'CompC')
+ // const switchToA = () => {
+ // current.value = 'CompA'
+ // includeRef.value = ['CompA']
+ // }
+ // return { current, switchToB, switchToC, switchToA, includeRef }
+ // },
+ // }).mount('#app')
+ // })
+
+ // await transitionFinish()
+ // expect(await html('#container')).toBe('CompA
')
+
+ // await click('#switchToB')
+ // await nextTick()
+ // await click('#switchToC')
+ // await transitionFinish()
+ // expect(await html('#container')).toBe('CompC
')
+
+ // await click('#switchToA')
+ // await transitionFinish()
+ // expect(await html('#container')).toBe('CompA
')
+
+ // // expect CompA only update once
+ // expect(onUpdatedSpyA).toBeCalledTimes(1)
+ // expect(onUnmountedSpyC).toBeCalledTimes(1)
+ // },
+ // E2E_TIMEOUT,
+ // )
+
+ // // #10827
+ // test(
+ // 'switch and update child then update include (out-in mode)',
+ // async () => {
+ // const onUnmountedSpyB = vi.fn()
+ // await page().exposeFunction('onUnmountedSpyB', onUnmountedSpyB)
+
+ // await page().evaluate(() => {
+ // const { onUnmountedSpyB } = window as any
+ // const {
+ // createApp,
+ // ref,
+ // shallowRef,
+ // h,
+ // provide,
+ // inject,
+ // onUnmounted,
+ // } = (window as any).Vue
+ // createApp({
+ // template: `
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ // `,
+ // components: {
+ // CompA: {
+ // name: 'CompA',
+ // setup() {
+ // const current = inject('current')
+ // return () => h('div', current.value)
+ // },
+ // },
+ // CompB: {
+ // name: 'CompB',
+ // setup() {
+ // const current = inject('current')
+ // onUnmounted(onUnmountedSpyB)
+ // return () => h('div', current.value)
+ // },
+ // },
+ // },
+ // setup: () => {
+ // const includeRef = ref(['CompA'])
+ // const current = shallowRef('CompA')
+ // provide('current', current)
+
+ // const switchToB = () => {
+ // current.value = 'CompB'
+ // includeRef.value = ['CompA', 'CompB']
+ // }
+ // const switchToA = () => {
+ // current.value = 'CompA'
+ // includeRef.value = ['CompA']
+ // }
+ // return { current, switchToB, switchToA, includeRef }
+ // },
+ // }).mount('#app')
+ // })
+
+ // await transitionFinish()
+ // expect(await html('#container')).toBe('CompA
')
+
+ // await click('#switchToB')
+ // await transitionFinish()
+ // await transitionFinish()
+ // expect(await html('#container')).toBe('CompB
')
+
+ // await click('#switchToA')
+ // await transitionFinish()
+ // await transitionFinish()
+ // expect(await html('#container')).toBe('CompA
')
+
+ // expect(onUnmountedSpyB).toBeCalledTimes(1)
+ // },
+ // E2E_TIMEOUT,
+ // )
+
+ // // #12860
+ // test(
+ // 'unmount children',
+ // async () => {
+ // const unmountSpy = vi.fn()
+ // let storageContainer: ElementHandle
+ // const setStorageContainer = (container: any) =>
+ // (storageContainer = container)
+ // await page().exposeFunction('unmountSpy', unmountSpy)
+ // await page().exposeFunction('setStorageContainer', setStorageContainer)
+ // await page().evaluate(() => {
+ // const { unmountSpy, setStorageContainer } = window as any
+ // const { createApp, ref, h, onUnmounted, getCurrentInstance } = (
+ // window as any
+ // ).Vue
+ // createApp({
+ // template: `
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ // `,
+ // components: {
+ // TrueBranch: {
+ // name: 'TrueBranch',
+ // setup() {
+ // const instance = getCurrentInstance()
+ // onUnmounted(() => {
+ // unmountSpy()
+ // setStorageContainer(instance.__keepAliveStorageContainer)
+ // })
+ // const count = ref(0)
+ // return () => h('div', count.value)
+ // },
+ // },
+ // },
+ // setup: () => {
+ // const includeRef = ref(['TrueBranch'])
+ // const toggle = ref(true)
+ // const click = () => {
+ // toggle.value = !toggle.value
+ // if (toggle.value) {
+ // includeRef.value = ['TrueBranch']
+ // } else {
+ // includeRef.value = []
+ // }
+ // }
+ // return { toggle, click, unmountSpy, includeRef }
+ // },
+ // }).mount('#app')
+ // })
+
+ // await transitionFinish()
+ // expect(await html('#container')).toBe('0
')
+
+ // await click('#toggleBtn')
+ // await transitionFinish()
+ // expect(await html('#container')).toBe('')
+ // expect(unmountSpy).toBeCalledTimes(1)
+ // expect(await storageContainer!.evaluate(x => x.innerHTML)).toBe(``)
+ // },
+ // E2E_TIMEOUT,
+ // )
+
+ // // #13153
+ // test(
+ // 'move kept-alive node before v-show transition leave finishes',
+ // async () => {
+ // await page().evaluate(() => {
+ // const { createApp, ref } = (window as any).Vue
+ // const show = ref(true)
+ // createApp({
+ // template: `
+ //
+ //
+ //
+ //
+ //
+ //
+ // `,
+ // setup: () => {
+ // const state = ref(1)
+ // const click = () => (state.value = state.value === 1 ? 2 : 1)
+ // return { state, click }
+ // },
+ // components: {
+ // Comp1: {
+ // components: {
+ // Item: {
+ // name: 'Item',
+ // setup() {
+ // return { show }
+ // },
+ // template: `
+ //
+ //
+ //
{{ show ? "I should show" : "I shouldn't show " }}
+ //
+ //
+ // `,
+ // },
+ // },
+ // name: 'Comp1',
+ // setup() {
+ // const toggle = () => (show.value = !show.value)
+ // return { show, toggle }
+ // },
+ // template: `
+ //
+ // This is page1
+ //
+ // `,
+ // },
+ // Comp2: {
+ // name: 'Comp2',
+ // template: `This is page2
`,
+ // },
+ // },
+ // }).mount('#app')
+ // })
+
+ // expect(await html('#container')).toBe(
+ // `I should show
` +
+ // `This is page1
` +
+ // ``,
+ // )
+
+ // // trigger v-show transition leave
+ // await click('#changeShowBtn')
+ // await nextTick()
+ // expect(await html('#container')).toBe(
+ // `I shouldn't show
` +
+ // `This is page1
` +
+ // ``,
+ // )
+
+ // // switch to page2, before leave finishes
+ // // expect v-show element's display to be none
+ // await click('#toggleBtn')
+ // await nextTick()
+ // expect(await html('#container')).toBe(
+ // `I shouldn't show
` +
+ // `This is page2
`,
+ // )
+
+ // // switch back to page1
+ // // expect v-show element's display to be none
+ // await click('#toggleBtn')
+ // await nextTick()
+ // expect(await html('#container')).toBe(
+ // `I shouldn't show
` +
+ // `This is page1
` +
+ // ``,
+ // )
+
+ // await transitionFinish()
+ // expect(await html('#container')).toBe(
+ // `I shouldn't show
` +
+ // `This is page1
` +
+ // ``,
+ // )
+ // },
+ // E2E_TIMEOUT,
+ // )
})
describe.todo('transition with Suspense', () => {})
diff --git a/packages-private/vapor-e2e-test/transition/App.vue b/packages-private/vapor-e2e-test/transition/App.vue
index e7227ded01e..7b802f768bc 100644
--- a/packages-private/vapor-e2e-test/transition/App.vue
+++ b/packages-private/vapor-e2e-test/transition/App.vue
@@ -9,6 +9,7 @@ import {
template,
defineVaporAsyncComponent,
onUnmounted,
+ onUpdated,
} from 'vue'
const show = ref(true)
const toggle = ref(true)
@@ -31,6 +32,7 @@ let calls = {
showAppear: [],
notEnter: [],
+ updated: [],
unmount: [],
}
window.getCalls = key => calls[key]
@@ -117,6 +119,42 @@ const click = () => {
includeRef.value = []
}
}
+
+const CompA = defineVaporComponent({
+ name: 'CompA',
+ setup() {
+ onUpdated(() => {
+ calls.updated.push('CompA updated')
+ })
+ return template('CompA
')()
+ },
+})
+
+const CompB = defineVaporComponent({
+ name: 'CompB',
+ setup() {
+ return template('CompB
')()
+ },
+})
+
+const CompC = defineVaporComponent({
+ name: 'CompC',
+ setup() {
+ onUnmounted(() => {
+ calls.unmount.push('CompC unmounted')
+ })
+ return template('CompC
')()
+ },
+})
+
+const includeToChange = ref(['CompA', 'CompB', 'CompC'])
+const currentView = shallowRef(CompA)
+const switchToB = () => (currentView.value = CompB)
+const switchToC = () => (currentView.value = CompC)
+const switchToA = () => {
+ currentView.value = CompA
+ includeToChange.value = ['CompA']
+}
@@ -545,6 +583,18 @@ const click = () => {
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/runtime-core/src/index.ts b/packages/runtime-core/src/index.ts
index 9e589ef9156..068184e8265 100644
--- a/packages/runtime-core/src/index.ts
+++ b/packages/runtime-core/src/index.ts
@@ -133,6 +133,7 @@ export {
export { withDirectives } from './directives'
// SSR context
export { useSSRContext, ssrContextKey } from './helpers/useSsrContext'
+export { MoveType } from './renderer'
// Custom Renderer API ---------------------------------------------------------
@@ -519,11 +520,7 @@ export { type VaporInteropInterface } from './apiCreateApp'
/**
* @internal
*/
-export {
- type RendererInternals,
- MoveType,
- getInheritedScopeIds,
-} from './renderer'
+export { type RendererInternals, getInheritedScopeIds } from './renderer'
/**
* @internal
*/
diff --git a/packages/runtime-vapor/__tests__/hmr.spec.ts b/packages/runtime-vapor/__tests__/hmr.spec.ts
index 3618ee10644..88be0bbabdc 100644
--- a/packages/runtime-vapor/__tests__/hmr.spec.ts
+++ b/packages/runtime-vapor/__tests__/hmr.spec.ts
@@ -276,11 +276,14 @@ describe('hot module replacement', () => {
components: { Child },
setup() {
const toggle = ref(true)
- return { toggle }
+ function onLeave(_: any, done: Function) {
+ setTimeout(done, 0)
+ }
+ return { toggle, onLeave }
},
render: compileToFunction(
`
-
+
`,
),
@@ -303,6 +306,7 @@ describe('hot module replacement', () => {
render: compileToFunction(`{{ count }}
`),
})
await nextTick()
+ await new Promise(r => setTimeout(r, 0))
expect(root.innerHTML).toBe(`1
`)
expect(unmountSpy).toHaveBeenCalledTimes(1)
expect(mountSpy).toHaveBeenCalledTimes(1)
diff --git a/packages/runtime-vapor/src/block.ts b/packages/runtime-vapor/src/block.ts
index 323ef7beefc..090ba1b4d84 100644
--- a/packages/runtime-vapor/src/block.ts
+++ b/packages/runtime-vapor/src/block.ts
@@ -8,6 +8,7 @@ import {
import { _child } from './dom/node'
import { isComment, isHydrating } from './dom/hydration'
import {
+ MoveType,
type TransitionHooks,
type TransitionProps,
type TransitionState,
@@ -77,6 +78,8 @@ export function insert(
block: Block,
parent: ParentNode & { $fc?: Node | null },
anchor: Node | null | 0 = null, // 0 means prepend
+ moveType: MoveType = MoveType.ENTER,
+ parentComponent?: VaporComponentInstance,
parentSuspense?: any, // TODO Suspense
): void {
anchor = anchor === 0 ? parent.$fc || _child(parent) : anchor
@@ -88,10 +91,23 @@ export function insert(
(block as TransitionBlock).$transition &&
!(block as TransitionBlock).$transition!.disabled
) {
- performTransitionEnter(
+ const action =
+ moveType === MoveType.LEAVE
+ ? performTransitionLeave
+ : performTransitionEnter
+
+ action(
block,
(block as TransitionBlock).$transition as TransitionHooks,
- () => parent.insertBefore(block, anchor as Node),
+ () => {
+ // if the component is unmounted after leave finish, remove the block
+ // to avoid retaining a detached node.
+ if (moveType === MoveType.LEAVE && parentComponent!.isUnmounted) {
+ block.remove()
+ } else {
+ parent.insertBefore(block, anchor as Node)
+ }
+ },
parentSuspense,
)
} else {
diff --git a/packages/runtime-vapor/src/component.ts b/packages/runtime-vapor/src/component.ts
index 002783fe429..8ef656ea92b 100644
--- a/packages/runtime-vapor/src/component.ts
+++ b/packages/runtime-vapor/src/component.ts
@@ -920,7 +920,7 @@ export function unmountComponent(
}
if (instance.isMounted && !instance.isUnmounted) {
- if (__DEV__ && instance.type.__hmrId) {
+ if (__DEV__) {
unregisterHMR(instance)
}
if (instance.bum) {
diff --git a/packages/runtime-vapor/src/components/KeepAlive.ts b/packages/runtime-vapor/src/components/KeepAlive.ts
index 2c267b001ed..3eaefcba3c4 100644
--- a/packages/runtime-vapor/src/components/KeepAlive.ts
+++ b/packages/runtime-vapor/src/components/KeepAlive.ts
@@ -3,6 +3,7 @@ import {
type GenericComponent,
type GenericComponentInstance,
type KeepAliveProps,
+ MoveType,
type VNode,
currentInstance,
devtoolsComponentAdded,
@@ -126,7 +127,7 @@ export const VaporKeepAliveImpl: ObjectVaporComponent = defineVaporComponent({
const processFragment = (frag: DynamicFragment) => {
const [innerBlock, interop] = getInnerBlock(frag.nodes)
- if (!innerBlock || !shouldCache(innerBlock!, props, interop)) return
+ if (!innerBlock || !shouldCache(innerBlock!, props, interop)) return false
if (interop) {
if (cache.has(innerBlock.vnode!.type)) {
@@ -139,6 +140,7 @@ export const VaporKeepAliveImpl: ObjectVaporComponent = defineVaporComponent({
}
innerBlock!.shapeFlag! |= ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE
}
+ return true
}
const cacheFragment = (fragment: DynamicFragment) => {
@@ -235,9 +237,13 @@ export const VaporKeepAliveImpl: ObjectVaporComponent = defineVaporComponent({
const injectKeepAliveHooks = (frag: DynamicFragment) => {
;(frag.onBeforeTeardown || (frag.onBeforeTeardown = [])).push(
(oldKey, nodes, scope) => {
- processFragment(frag)
- keptAliveScopes.set(oldKey, scope)
- return true
+ // if the fragment's nodes include a component that should be cached
+ // return true to avoid tearing down the fragment's scope
+ if (processFragment(frag)) {
+ keptAliveScopes.set(oldKey, scope)
+ return true
+ }
+ return false
},
)
;(frag.onBeforeMount || (frag.onBeforeMount = [])).push(() =>
@@ -358,7 +364,7 @@ export function deactivate(
instance: VaporComponentInstance,
container: ParentNode,
): void {
- insert(instance.block, container)
+ insert(instance.block, container, null, MoveType.LEAVE, instance)
queuePostFlushCb(() => {
if (instance.da) invokeArrayFns(instance.da)
diff --git a/packages/runtime-vapor/src/components/Transition.ts b/packages/runtime-vapor/src/components/Transition.ts
index 00871ff2bf1..73593d47d76 100644
--- a/packages/runtime-vapor/src/components/Transition.ts
+++ b/packages/runtime-vapor/src/components/Transition.ts
@@ -27,7 +27,7 @@ import {
} from '../component'
import { isArray } from '@vue/shared'
import { renderEffect } from '../renderEffect'
-import { isFragment } from '../fragment'
+import { type VaporFragment, isFragment } from '../fragment'
import {
currentHydrationNode,
isHydrating,
@@ -80,29 +80,16 @@ export const VaporTransition: FunctionalVaporComponent =
checkTransitionMode(mode)
let resolvedProps: BaseTransitionProps
- let isMounted = false
- renderEffect(() => {
- resolvedProps = resolveTransitionProps(props)
- if (isMounted) {
- // only update props for Fragment transition, for later reusing
- if (isFragment(children)) {
- children.$transition!.props = resolvedProps
- } else {
- const child = findTransitionBlock(children)
- if (child) {
- // replace existing transition hooks
- child.$transition!.props = resolvedProps
- applyTransitionHooks(child, child.$transition!, true)
- }
- }
- } else {
- isMounted = true
- }
- })
+ renderEffect(() => (resolvedProps = resolveTransitionProps(props)))
const hooks = applyTransitionHooks(children, {
state: useTransitionState(),
- props: resolvedProps!,
+ // use proxy to keep props reference stable
+ props: new Proxy({} as BaseTransitionProps, {
+ get(_, key) {
+ return resolvedProps[key as keyof BaseTransitionProps]
+ },
+ }),
instance: instance,
} as VaporTransitionHooks)
@@ -185,7 +172,6 @@ export function resolveTransitionHooks(
export function applyTransitionHooks(
block: Block,
hooks: VaporTransitionHooks,
- isResolved: boolean = false,
): VaporTransitionHooks {
// filter out comment nodes
if (isArray(block)) {
@@ -197,13 +183,15 @@ export function applyTransitionHooks(
}
}
- const isFrag = isFragment(block)
- const child = isResolved
- ? (block as TransitionBlock)
- : findTransitionBlock(block, isFrag)
+ const fragments: VaporFragment[] = []
+ const child = findTransitionBlock(block, frag => fragments.push(frag))
if (!child) {
- // set transition hooks on fragment for reusing during it's updating
- if (isFrag) setTransitionHooksOnFragment(block, hooks)
+ // set transition hooks on fragments for later use
+ fragments.forEach(f => (f.$transition = hooks))
+ // warn if no child and no fragments
+ if (__DEV__ && fragments.length === 0) {
+ warn('Transition component has no valid child element')
+ }
return hooks
}
@@ -217,7 +205,7 @@ export function applyTransitionHooks(
)
resolvedHooks.delayedLeave = delayedLeave
child.$transition = resolvedHooks
- if (isFrag) setTransitionHooksOnFragment(block, resolvedHooks)
+ fragments.forEach(f => (f.$transition = resolvedHooks))
return resolvedHooks
}
@@ -273,7 +261,7 @@ export function applyTransitionLeaveHooks(
export function findTransitionBlock(
block: Block,
- inFragment: boolean = false,
+ onFragment?: (frag: VaporFragment) => void,
): TransitionBlock | undefined {
let child: TransitionBlock | undefined
if (block instanceof Node) {
@@ -286,7 +274,7 @@ export function findTransitionBlock(
} else {
// stop searching if encountering nested Transition component
if (getComponentName(block.type) === displayName) return undefined
- child = findTransitionBlock(block.block, inFragment)
+ child = findTransitionBlock(block.block, onFragment)
// use component id as key
if (child && child.$key === undefined) child.$key = block.uid
}
@@ -294,9 +282,7 @@ export function findTransitionBlock(
let hasFound = false
for (const c of block) {
if (c instanceof Comment) continue
- // check if the child is a fragment to suppress warnings
- if (isFragment(c)) inFragment = true
- const item = findTransitionBlock(c, inFragment)
+ const item = findTransitionBlock(c, onFragment)
if (__DEV__ && hasFound) {
// warn more than one non-comment child
warn(
@@ -310,19 +296,15 @@ export function findTransitionBlock(
if (!__DEV__) break
}
} else if (isFragment(block)) {
- // mark as in fragment to suppress warnings
- inFragment = true
if (block.insert) {
child = block
} else {
- child = findTransitionBlock(block.nodes, true)
+ // collect fragments for setting transition hooks
+ if (onFragment) onFragment(block)
+ child = findTransitionBlock(block.nodes, onFragment)
}
}
- if (__DEV__ && !child && !inFragment) {
- warn('Transition component has no valid child element')
- }
-
return child
}
diff --git a/packages/runtime-vapor/src/components/TransitionGroup.ts b/packages/runtime-vapor/src/components/TransitionGroup.ts
index 76d5acd1c1a..7055b612333 100644
--- a/packages/runtime-vapor/src/components/TransitionGroup.ts
+++ b/packages/runtime-vapor/src/components/TransitionGroup.ts
@@ -21,6 +21,7 @@ import {
type VaporTransitionHooks,
insert,
} from '../block'
+import { renderEffect } from '../renderEffect'
import {
resolveTransitionHooks,
setTransitionHooks,
@@ -55,7 +56,18 @@ export const VaporTransitionGroup: ObjectVaporComponent = decorate({
setup(props: TransitionGroupProps, { slots }) {
const instance = currentInstance as VaporComponentInstance
const state = useTransitionState()
- const cssTransitionProps = resolveTransitionProps(props)
+
+ // use proxy to keep props reference stable
+ let cssTransitionProps = resolveTransitionProps(props)
+ const propsProxy = new Proxy({} as typeof cssTransitionProps, {
+ get(_, key) {
+ return cssTransitionProps[key as keyof typeof cssTransitionProps]
+ },
+ })
+
+ renderEffect(() => {
+ cssTransitionProps = resolveTransitionProps(props)
+ })
let prevChildren: TransitionBlock[]
let children: TransitionBlock[]
@@ -121,7 +133,7 @@ export const VaporTransitionGroup: ObjectVaporComponent = decorate({
// store props and state on fragment for reusing during insert new items
setTransitionHooksOnFragment(slottedBlock, {
- props: cssTransitionProps,
+ props: propsProxy,
state,
instance,
} as VaporTransitionHooks)
@@ -133,7 +145,7 @@ export const VaporTransitionGroup: ObjectVaporComponent = decorate({
if (child.$key != null) {
const hooks = resolveTransitionHooks(
child,
- cssTransitionProps,
+ propsProxy,
state,
instance!,
)
diff --git a/packages/runtime-vapor/src/fragment.ts b/packages/runtime-vapor/src/fragment.ts
index 58cf1707162..6d73ceb088a 100644
--- a/packages/runtime-vapor/src/fragment.ts
+++ b/packages/runtime-vapor/src/fragment.ts
@@ -118,6 +118,7 @@ export class DynamicFragment extends VaporFragment {
if (isHydrating) this.hydrate(true)
return
}
+ const prevKey = this.current
this.current = key
const instance = currentInstance
@@ -130,9 +131,11 @@ export class DynamicFragment extends VaporFragment {
// if any of the hooks returns true the scope will be preserved
// for kept-alive component
if (this.onBeforeTeardown) {
- preserveScope = this.onBeforeTeardown.some(hook =>
- hook(this.current, this.nodes, this.scope!),
- )
+ for (const teardown of this.onBeforeTeardown) {
+ if (teardown(prevKey, this.nodes, this.scope!)) {
+ preserveScope = true
+ }
+ }
}
if (!preserveScope) {
this.scope.stop()