slots are now functions instead of arrays
Version
3.0.0-rc.10
Reproduction link
v2: https://codesandbox.io/s/new-silence-wx19w?file=/src/components/Provider.js
v3 https://codesandbox.io/s/eager-currying-uqj9y?file=/src/Provider.js
Steps to reproduce
Run this:
import { h } from 'vue';
export default {
render() {
return h('div', {}, this.$slots.default);
},
};
and use it like <Provider> some content </Provider>
What is expected?
this.$slots.default
renders the children
What is actually happening?
this.$slots.default()
renders the children
I'm trying to make a library compatible with v2 & v3 at the same time, but I had a hard time finding out that slots now need to be called. In https://v3.vuejs.org/guide/migration/slots-unification.html#_3-x-syntax this doesn't seem to be mentioned
Workaround I found:
import { h } from "vue";
export default {
render(localH) {
return (h || localH)(
"div",
{},
typeof this.$slots.default === "function"
? this.$slots.default()
: this.$slots.default
);
}
};
Should this be documented or am I missing something? Thanks!
This is a documented change: https://github.com/vuejs/rfcs/blob/master/active-rfcs/0006-slots-unification.md
I see now, but it wasn't too straightforward since it wasn't mentioned in the "migration strategy" key. I'll make a pull request to add it a little more explicit, since I think I looked at least 30 minutes why it wasn't displaying anything :)
The migration guide, as it currently stands, assume you're migrating from 2.6+ vm.$scopedSlots
instead of the soft-deprecated 2.x vm.$slots
(see RFC and announcement).
vm.$scopedSlots
entries are always functions and, since 2.6, all slots in vm.$slots
are also present, as a function, in vm.$scopedSlots
. Always returning a function has performance benefits, and the semantics are more similar to 3.x vm.$slots
.
So, to be compatible with both 2.x and 3.x, a better approach is supporting this.$scopedSlots.header()
in 2.x and this.$slots.header()
in 3.x instead of this.$slots.header
in 2.x and this.$slots.header()
in 3.x.