-
Notifications
You must be signed in to change notification settings - Fork 342
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
context.slots is empty in setup() #84
Comments
Getting export default createComponent({
setup: () => (_, { slots }) => <div>{slots.default()}</div>
}) |
@PatrykWalach yes it works, thanks man. |
The |
@liximomo thanks for explanation, that totally makes sense and reasonable, however I'm still wondering if this is a limitation of composition-api plugin (due to the lack of Vue 2 api?) or it's a part of Vue 3.0 composition. For Vue 3.0 official if I can destruct { slots } from setup context already, but cannot use in setup function, and have to do it again in render function, then it's a bit confuse to me. Btw, I checked render function api change again and see that for vue 3, render function 2nd parameter should be slots, not context, a bit more confuse here 😅 In my case, the reason I need slots out of render() is becus I don't wanna compose the logic inside render function (I only put jsx there mainly for markup) I simplified the situation here... import { computed, createElement as h } from '@vue/composition-api'
export default {
name: 'ListView',
props: {
data: { type: Array, default: () => [] }
},
setup: (props, { slots }) => {
// simplified composition logics
const renderItem = (item) => {
return slots.default && slots.default(item) || <li>{item}</li>
}
const listItems = data.map(renderItem)
// Simplified jsx to avoid confusion
return () => (
<ul>
{listItems}
</ul>
)
}
} At the moment since I don't have slots access out of render() so I have to either:
|
You can create a function, then call it in the render function. And it's not safe to call slots out of Based on your example: import { computed, createElement as h } from '@vue/composition-api'
export default {
name: 'ListView',
props: {
data: { type: Array, default: () => [] }
},
setup: (props, { slots }) => {
// simplified composition logics
const renderItem = (item) => {
return slots.default && slots.default(item) || <li>{item}</li>
}
const renderItems = () => data.map(renderItem);
// Simplified jsx to avoid confusion
return () => (
<ul>
{renderItems()}
</ul>
)
}
} |
@liximomo thanks for your reply, I tried again, this doesn't work import { createElement as h } from '@vue/composition-api'
export default {
name: 'ListView',
props: {
data: { type: Array, default: () => [] }
},
setup: (props, { slots }) => {
const renderItems = () => data.map(item => {
return slots.default && slots.default(item) || <li>{item}</li>
});
return () => (
<ul>
{renderItems()}
</ul>
)
}
} But this works import { createElement as h } from '@vue/composition-api'
export default {
name: 'ListView',
props: {
data: { type: Array, default: () => [] }
},
setup: (props, { slots }) => {
const renderItems = (slots) => data.map((item => {
return slots.default && slots.default(item) || <li>{item}</li>
})
return (_, { slots }) => (
<ul>
{renderItems(slots)}
</ul>
)
}
} Like I said earlier
So what's the point of setup() context.slots, it must be there for some reason, right? |
Looks like Vue 2 created a new object for |
Disclaimer: This is my own perspective of the issue as a developer who works with So from my understanding, there are three questions here:
Well, as @liximomo already stated, the You are trying to use
Nuff said, how to separate rendering & the setup stuff? Let's say I want to have a component <foobar foo="bar">
<div attr="val"/>
<div foo="bar"/>
<p title="not you"/>
</foobar>
<!-- expected:
{ "attr": "val" }
{ "foo": "bar" }
--> The "normal" way <template>
<div class="items">
<div v-for="(item, index) in items" :key="index">
{{ item }}
</div>
</div>
</template>
<script>
export default {
data () {
return {
slots: []
}
},
computed: {
items () {
return this.slots
.filter(vnode => {
return vnode.tag === 'div'
})
.map(vnode => {
return vnode.data.attrs
})
}
},
created () {
this.slots = this.$slots.default || []
}
}
</script> The composition way <template>
<div class="items">
<div v-for="(item, index) in state.items" :key="index">
{{ item }}
</div>
</div>
</template>
<script>
import { reactive, computed, onMounted } from '@vue/composition-api'
export default {
setup (props, context) {
const state = reactive({
slots: [],
items: computed(() => {
return state.slots
.filter(vnode => {
return vnode.tag === 'div'
})
.map(vnode => {
return vnode.data.attrs
})
})
})
onMounted(() => {
// onCreated is deprecated https://github.com/vuejs/composition-api/blob/9d8855a4a293321075c93b15d631a43681c2605b/src/apis/lifecycle.ts#L30
state.slots = context.slots.default() || []
})
return {
state
}
}
}
</script> As you can see, |
I was trying to solve the reactivity problem but it doesn't fit right with the original issue from @tiepnguyen. As you can see, the data () {
return {
slots: this.$slots.default
}
} So I decided to take a close look at the two libraries and did notice the difference between As you can see, $scopedSlots is not initiated until Despite the documentation:
I think So, summary?
|
@hiendv thanks for your big effort and detail explanation, your solution of shadow copy So at the moment I'll just either
|
Per spec:
|
@yyx990803 If we recommend people "to always access slots via $scopedSlots, whether they currently use a scope or not", I think we should initial |
@yyx990803 Thanks, Evan. Just to be clear, for this plugin, we will keep the references to slots and scoped slots separately right? Or we keep unifying them, let scopedSlots have the initial value of slots? |
Nvm, I saw the commit. 3b8cfc2 |
I'm not sure if this is an issue or I'm doing something wrong, but currently I got "context.slots" an empty object in setup(), although it's available in lifecycle hook functions
The thing is, I need {slots.default} for render function / JSX inside setup(), so I can't use this.$slots.default either since "this" is not available in setup().
If I try to destruct context to { slots } then it even empty inside onMounted function
The text was updated successfully, but these errors were encountered: