Allow a single slot to be rendered for multiple times
See original GitHub issueWhat problem does this feature solve?
Currently if we render a slot for multiple times (eg. inside a v-for
loop), we’ll get
Duplicate presence of slot "${name}" found in the same render tree - this will likely cause render errors.
I know it’s intentional to prevent render errors (like losing correct data binding) but consider the following use case: I have a v-breadcrumbs
component which has a default item separator of a text node /
, and I want to allows users to specify their own separators which can be anything, like an <v-icon>
component.
Currently if I want to make it work, I have to define a scoped slot in the v-breadcrumbs
component and bind nothing to it:
<slot name="sep" v-bind="{}">/</slot>
And component users must define slot-scope
on it and not use anything from it:
<v-breadcrumbs>
<v-icon slot="sep" slot-scope="_" name="angle-right"/>
</v-breadcrumbs>
And currently Vue is using slots as fallbacks for scoped slots with the same name. Whether the users can use a slot doesn’t rely on if they want data from slot scope, but on whether the slot is gonna be rendered for multiple times inside the component self, this may raise more confusion for our users (like #8175).
So why don’t we just get rid of such caveats and let a slot to be rendered more than once? We can clone them on duplication to prevent render errors as we already run the scoped slot function each time anyway. This makes the logic a lot simpler for users IMO: if we do not expect to use data from the slot scope, just use a slot, otherwise we’ll always have to declare slot-scope
to create the binding.
In addition, this would make documenting the (scoped) slots of a component more consistent, we just declare the data structure for a slot scope and users can decide if they want some data to bind to the slot-scope
and don’t need to care about how many times it will be rendered.
What does the proposed API look like?
No additional API needed, just clone the slot nodes upon render and remove the waring about duplicated slots.
It may be implemented in userland today in a quite hacky way, see: https://codesandbox.io/s/lp11y2wovz
I just tweaked the cloneVNode
function from the Vue core a little bit and it seemed to be working as expected using render function (without losing reactivity and event binding). There maybe some other edge situations I missed so correct me if it’s not such trivial.
Issue Analytics
- State:
- Created 5 years ago
- Reactions:13
- Comments:12 (6 by maintainers)
Top GitHub Comments
Resolved by 530ca1b2db315fbd0e360807b2031d26665c5d3d and shipped with
vue@2.5.18-beta.0
. Cheers! 🎉another benefit of always using scopedSlots insteadof slots is lazy evaluation of slot content: Imagine a component with the following template
loading(:while="!item") {{ item.name }}
The loading comp wouldnt display the slot content until item becomes truthy, but “normal” slots are rendered eagerly causing errors despite the slot content not being displayed.