Skip to content

Commit 51ee84f

Browse files
committed
fix(suspense): fix dynamicChildren tracking when suspense root is a block itself
e.g. `<slot>` inside suspense fix #4183, fix #4198
1 parent 1867591 commit 51ee84f

File tree

2 files changed

+52
-2
lines changed

2 files changed

+52
-2
lines changed

packages/runtime-core/__tests__/rendererOptimizedMode.spec.ts

+51-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ import {
2222
SetupContext,
2323
createApp,
2424
FunctionalComponent,
25-
renderList
25+
renderList,
26+
onUnmounted
2627
} from '@vue/runtime-test'
2728
import { PatchFlags, SlotFlags } from '@vue/shared'
2829
import { SuspenseImpl } from '../src/components/Suspense'
@@ -826,6 +827,55 @@ describe('renderer: optimized mode', () => {
826827
expect(inner(root)).toBe('<div><div>true</div></div>')
827828
})
828829

830+
// #4183
831+
test('should not take unmount children fast path /w Suspense', async () => {
832+
const show = ref(true)
833+
const spyUnmounted = jest.fn()
834+
835+
const Parent = {
836+
setup(props: any, { slots }: SetupContext) {
837+
return () => (
838+
openBlock(),
839+
createBlock(SuspenseImpl, null, {
840+
default: withCtx(() => [renderSlot(slots, 'default')]),
841+
_: SlotFlags.FORWARDED
842+
})
843+
)
844+
}
845+
}
846+
847+
const Child = {
848+
setup() {
849+
onUnmounted(spyUnmounted)
850+
return () => createVNode('div', null, show.value, PatchFlags.TEXT)
851+
}
852+
}
853+
854+
const app = createApp({
855+
render() {
856+
return show.value
857+
? (openBlock(),
858+
createBlock(
859+
Parent,
860+
{ key: 0 },
861+
{
862+
default: withCtx(() => [createVNode(Child)]),
863+
_: SlotFlags.STABLE
864+
}
865+
))
866+
: createCommentVNode('v-if', true)
867+
}
868+
})
869+
870+
app.mount(root)
871+
expect(inner(root)).toBe('<div>true</div>')
872+
873+
show.value = false
874+
await nextTick()
875+
expect(inner(root)).toBe('<!--v-if-->')
876+
expect(spyUnmounted).toHaveBeenCalledTimes(1)
877+
})
878+
829879
// #3881
830880
// root cause: fragment inside a compiled slot passed to component which
831881
// programmatically invokes the slot. The entire slot should de-opt but

packages/runtime-core/src/components/Suspense.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -749,7 +749,7 @@ function normalizeSuspenseSlot(s: any) {
749749
s = singleChild
750750
}
751751
s = normalizeVNode(s)
752-
if (block) {
752+
if (block && !s.dynamicChildren) {
753753
s.dynamicChildren = block.filter(c => c !== s)
754754
}
755755
return s

0 commit comments

Comments
 (0)