Skip to content

Commit

Permalink
fix(runtime-core): force diff slot fallback content and provided content
Browse files Browse the repository at this point in the history
fix #7256
fix #9200
fix #9308

close #7266
close #9213
  • Loading branch information
yyx990803 committed Jul 12, 2024
1 parent 685e3f3 commit d76dd9c
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 6 deletions.
6 changes: 5 additions & 1 deletion packages/runtime-core/__tests__/helpers/renderSlot.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,17 @@ describe('renderSlot', () => {
const vnode = renderSlot(
{ default: () => [(child = h('child'))] },
'default',
{ key: 'foo' },
)
expect(vnode.children).toEqual([child])
expect(vnode.key).toBe('foo')
})

it('should render slot fallback', () => {
const vnode = renderSlot({}, 'default', {}, () => ['fallback'])
const vnode = renderSlot({}, 'default', { key: 'foo' }, () => ['fallback'])
expect(vnode.children).toEqual(['fallback'])
// should attach fallback key postfix
expect(vnode.key).toBe('foo_fb')
})

it('should warn render ssr slot', () => {
Expand Down
73 changes: 73 additions & 0 deletions packages/runtime-core/__tests__/rendererOptimizedMode.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1105,4 +1105,77 @@ describe('renderer: optimized mode', () => {
expect(app.config.errorHandler).not.toHaveBeenCalled()
}
})

test('diff slot and slot fallback node', async () => {
const Comp = {
props: ['show'],
setup(props: any, { slots }: SetupContext) {
return () => {
return (
openBlock(),
createElementBlock('div', null, [
renderSlot(slots, 'default', { hide: !props.show }, () => [
(openBlock(),
(block = createElementBlock(
Fragment,
{ key: 0 },
[createTextVNode('foo')],
PatchFlags.STABLE_FRAGMENT,
))),
]),
])
)
}
},
}

const show = ref(true)
const app = createApp({
render() {
return (
openBlock(),
createBlock(
Comp,
{ show: show.value },
{
default: withCtx(({ hide }: { hide: boolean }) => [
!hide
? (openBlock(),
createElementBlock(
Fragment,
{ key: 0 },
[
createCommentVNode('comment'),
createElementVNode(
'div',
null,
'bar',
PatchFlags.HOISTED,
),
],
PatchFlags.STABLE_FRAGMENT,
))
: createCommentVNode('v-if', true),
]),
_: SlotFlags.STABLE,
},
PatchFlags.PROPS,
['show'],
)
)
},
})

app.mount(root)
expect(inner(root)).toBe('<div><!--comment--><div>bar</div></div>')
expect(block).toBe(null)

show.value = false
await nextTick()
expect(inner(root)).toBe('<div>foo</div>')

show.value = true
await nextTick()
expect(inner(root)).toBe('<div><!--comment--><div>bar</div></div>')
})
})
12 changes: 7 additions & 5 deletions packages/runtime-core/src/helpers/renderSlot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,13 @@ export function renderSlot(
Fragment,
{
key:
props.key ||
// slot content array of a dynamic conditional slot may have a branch
// key attached in the `createSlots` helper, respect that
(validSlotContent && (validSlotContent as any).key) ||
`_${name}`,
(props.key ||
// slot content array of a dynamic conditional slot may have a branch
// key attached in the `createSlots` helper, respect that
(validSlotContent && (validSlotContent as any).key) ||
`_${name}`) +
// #7256 force differentiate fallback content from actual content
(!validSlotContent && fallback ? '_fb' : ''),
},
validSlotContent || (fallback ? fallback() : []),
validSlotContent && (slots as RawSlots)._ === SlotFlags.STABLE
Expand Down

0 comments on commit d76dd9c

Please sign in to comment.