diff --git a/packages/runtime-core/__tests__/rendererOptimizedMode.spec.ts b/packages/runtime-core/__tests__/rendererOptimizedMode.spec.ts index 8c28d88102d..ef4f3ef8355 100644 --- a/packages/runtime-core/__tests__/rendererOptimizedMode.spec.ts +++ b/packages/runtime-core/__tests__/rendererOptimizedMode.spec.ts @@ -734,4 +734,54 @@ describe('renderer: optimized mode', () => { await nextTick() expect(inner(root)).toBe('

1

') }) + + // #3779 + test('treat slots manually written by the user as dynamic', async () => { + const Middle = { + setup(props: any, { slots }: any) { + return slots.default! + } + } + + const Comp = { + setup(props: any, { slots }: any) { + return () => { + return ( + openBlock(), + createBlock('div', null, [ + createVNode(Middle, null, { + default: withCtx( + () => [ + createVNode('div', null, [renderSlot(slots, 'default')]) + ], + undefined + ), + _: 3 /* FORWARDED */ + }) + ]) + ) + } + } + } + + const loading = ref(false) + const app = createApp({ + setup() { + return () => { + // important: write the slot content here + const content = h('span', loading.value ? 'loading' : 'loaded') + return h(Comp, null, { + default: () => content + }) + } + } + }) + + app.mount(root) + expect(inner(root)).toBe('
loaded
') + + loading.value = true + await nextTick() + expect(inner(root)).toBe('
loading
') + }) }) diff --git a/packages/runtime-core/src/vnode.ts b/packages/runtime-core/src/vnode.ts index 7e5976e2f7b..99adae44c01 100644 --- a/packages/runtime-core/src/vnode.ts +++ b/packages/runtime-core/src/vnode.ts @@ -651,12 +651,12 @@ export function normalizeChildren(vnode: VNode, children: unknown) { // a child component receives forwarded slots from the parent. // its slot type is determined by its parent's slot type. if ( - currentRenderingInstance.vnode.patchFlag & PatchFlags.DYNAMIC_SLOTS + (currentRenderingInstance.slots as RawSlots)._ === SlotFlags.STABLE ) { + ;(children as RawSlots)._ = SlotFlags.STABLE + } else { ;(children as RawSlots)._ = SlotFlags.DYNAMIC vnode.patchFlag |= PatchFlags.DYNAMIC_SLOTS - } else { - ;(children as RawSlots)._ = SlotFlags.STABLE } } }