Subscribe on changes!

Slots props are undefined while using both props destructuring and useSlots()

avatar
Sep 22nd 2021

Version

3.2.13

Reproduction link

codesandbox.io

Steps to reproduce

Parent.vue

<template>
  <Demo v-slot="{ item }">
    <div>{{ item }}</div>
  </Demo>
</template>

Child.vue

<template>
  <slot :item="111" />
</template>

<script setup>
import { useSlots } from 'vue'
console.log(useSlots().default())
</script>

What is expected?

Prop "item" should be usable (displays "111")

What is actually happening?

Props are undefined. Error Cannot destructure property 'item' of 'undefined' as it is undefined.


I have DataTable component where columns are defined in slot as DataTableColumn component for easy usage, like that:

<DataTable 
  :data="someData"
  v-slot="slotProps"
>
  <DataTableColumn name="id">
    <span class="xxxx">{{ slotProps.item.id }}</span>
  </DataTableColumn>
  <DataTableColumn name="email">
    {{ slotProps.item.email }} {{ slotProps.item.something }} etc
  </DataTableColumn>
</DataTable>

I'm getting columns list thanks to useSlots().default()

if (slots.default) {
  columns.value = slots.default()
    .filter((node) => node.props)
    .flatMap((node) => node.props)
}

current item (row) is passed as slot props to parent

<tr
  v-for="(item, key) in data"
  :key="key"
>
  <slot :item="item" />
</tr>

and it works great, I was using similar approach multiple times, also in vue 2.

Problem is that for some reason I cannot use object destructuring on slot props, like that:

<DataTable 
  :data="someData"
  v-slot="{ item }"
>
  <DataTableColumn name="id">
    <span class="xxxx">{{ item.id }}</span>
  </DataTableColumn>
  <DataTableColumn name="email">
    {{ item.email }} {{ item.something }} etc
  </DataTableColumn>
</DataTable>

In console I'm getting TypeError: Cannot destructure property 'item' of 'undefined' as it is undefined.

It's caused only by using default() in code. Why it is undefined while firing default(), even in onMounted()? So why is default() working alone, and { item } is working alone, but not both combined? For me it's bug, but maybe I'm wrong and someone will clarify this.

avatar
Sep 22nd 2021

You need to pass the relevant information to the slot, in this case item:

useSlots().default({ item })
avatar
Sep 23rd 2021

You need to pass the relevant information to the slot, in this case item:

useSlots().default({ item })

default({}) is working just fine, thanks!