1

The full warning message:

[Vue warn]: Slot "default" invoked outside of the render function: this will not track dependencies used in the slot. Invoke the slot function inside the render function instead.

Nothing is broken and the functionality runs fine. I am just trying to clear this error.

Here is my code:

<template>
  <ul class="flex" data-test-id="tab-wrapper">
    <li
      v-for="(tab, index) in tabs"
      :key="index"
      @click="currentTab = tab"
    >
      {{ tab }}
    </li>
  </ul>
  <slot />
</template>


<script setup>
import { provide, ref, useSlots } from "vue";

const slots = useSlots();
const tabs = (slots.default && slots.default().map(tab => tab?.props?.title)) ?? [];
const currentTab = ref(tabs[0]);

provide("currentTab", currentTab);
</script>

It is my understanding that render() is implicit in the template, but I don't know how to implement the way I am using slots in the template v-for.

Other questions that I have seen about this involve setup(props, context) or actually rendering the template using render() inside the script tag.

I'm brand new to Vue3/Composition API so I'm sure I did something wrong, but I'm having trouble figuring out exactly what. Any help is appreciated!

Cin88
  • 425
  • 2
  • 6
  • 20
  • Does this answer your question? [Vue 3 cli-service app: "Slot "default" invoked outside of the render function" warning when component with slots is imported from other component](https://stackoverflow.com/questions/69928229/vue-3-cli-service-app-slot-default-invoked-outside-of-the-render-function-w) – Tolbxela Mar 21 '23 at 17:35

2 Answers2

1

UPDATE

I've done it using render functions, just for sake of trying.

I would not do it this way in real, since it's too complicated and feels very like bad designed.

const { createApp, ref, h, resolveComponent } = Vue;

const Tab = {
  props: ['title'],
  template: 'Tab: {{ title }}'
}

const Tabpane = {
  components: { Tab },
  setup(props, { slots, expose }) {
    const currentTab = ref(null);
    const tab = resolveComponent('Tab')
    return () => h('div', null, 
      [
        h('div', null, 'Current Tab: ' + (currentTab.value ? currentTab.value.props?.title : '') ),
        h('ul', { class: 'flex', 'data-test-id' : 'tab-wrapper' }, 
         slots.default()?.map(tab => 
          h('li', 
            { onClick: () => { currentTab.value = tab } }, 
            tab.props.title)) ?? []          
        ),
        currentTab.value ? h(tab, 
          { title: currentTab.value?.props.title }, 
          currentTab 
        ) : null
     ])
  }
}

const App = { 
  components: { Tabpane }
}
const app = createApp(App)
app.mount('#app')
#app { line-height: 2; }
[v-cloak] { display: none; }
li { cursor: pointer; text-decoration: underline; color: blue;}
<div id="app" v-cloak>
<tabpane>
<tab title="One"></tab>
<tab title="Two"></tab>
</tabpane>
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script>
<script type="text/x-template" id="tabpane">
  <ul class="flex" data-test-id="tab-wrapper">
    <li
      v-for="(tab, index) in tabs" :key="index" @click="currentTab = tab">
      {{ tab }}
    </li>
  </ul>
  <slot></slot>
</script>

This is a duplicate of the Vue 3 cli-service app: "Slot "default" invoked outside of the render function" warning when component with slots is imported from other component

You should not use slots.default() outside the render() function.

That's what the Vue warning says.

Tolbxela
  • 4,767
  • 3
  • 21
  • 42
  • Thanks for the response. That answers my question on a conceptual level (I saw that post before), and I see how he did it with setup() inside defineComponent(), but I don't know how to transfer that implementation into the way my code is written. That's what I have been researching. I tried to actually write slots.default().map in the v-for tag but that did not work – Cin88 Mar 21 '23 at 19:26
  • Why not simply pass the tab titles over a prop? – Tolbxela Mar 21 '23 at 21:30
  • The component above is TabWrapper.vue. I am calling it inside a component as a wrapper for Tab.vue. The tab title is passed to each inside , so to access those values I need to check the slots in TabWrapper. It seems like the solution may be to refactor the way I did this. – Cin88 Mar 22 '23 at 14:46
  • 1
    Check the Vue Docs: [Dynamic Components](https://vuejs.org/guide/essentials/component-basics.html#dynamic-components) section for an example how to implement a tabulator. This is the recommended way to solve tasks like yours. – Tolbxela Mar 23 '23 at 09:36
0

I don't have reputation to comment, but the solution is put the context on the <slot></slot>

- The documentation

- here an example

  • Sorry, but the answer is wrong. -1 – Tolbxela Mar 21 '23 at 17:35
  • Thanks Everton, but I had read that doc as well. The person is calling the slots.default() inside the `return` of the setup() function. Different scenario from mine code-wise. Still trying to figure out how to do it. – Cin88 Mar 21 '23 at 19:29