wittgenstein
wittgenstein

Reputation: 4472

How to use <component :is=""> in vue 3 script setup

I am using the experimental script setup to create a learn enviroment. I got a selfmade navigation bar with open a single component.

I am having trouble using the <component :is="" /> method. This method is described in the docs under component basics -> dynamic-components

In the Vue 3 Composition API, it works as expected:

<template>
  <NavigationBar
    @switchTab="changeTab"
    :activeTab="tab"
  />
  <component :is="tab" />
</template>

<script>
import { ref } from 'vue'
import NavigationBar from './components/NavigationBar.vue'
import TemplateSyntax from './components/TemplateSyntax.vue'
import DataPropsAndMethods from './components/DataPropsAndMethods.vue'

export default {
  components: {
    NavigationBar,
    TemplateSyntax,
    DataPropsAndMethods
  },
  setup () {
    const tab = ref('DataPropsAndMethods')
    function changeTab (newTab) {
      tab.value = newTab
    }

    return {
      changeTab,
      tab
    }
  }
}
</script>

My approach with the script setup fails:

<template>
  <NavigationBar
    @switchTab="changeTab"
    :activeTab="tab"
  />
  <component :is="tab" />
</template>

<script setup>
import NavigationBar from './components/NavigationBar.vue'
import TemplateSyntax from './components/TemplateSyntax.vue'
import DataPropsAndMethods from './components/DataPropsAndMethods.vue'
import { ref } from 'vue'

const tab = ref('DataPropsAndMethods')
function changeTab (newTab) {
  tab.value = newTab
}
</script>

do you got any idea how to solve this with the script setup method?

Upvotes: 30

Views: 31696

Answers (2)

My approach :

<template>
  <NavigationBar
    @switchTab="changeTab"
    :activeTab="tab"
  />
  <component :is="activeTab" />
</template>

<script setup lang="ts">
import NavigationBar from './components/NavigationBar.vue'
import TemplateSyntax from './components/TemplateSyntax.vue'
import DataPropsAndMethods from './components/DataPropsAndMethods.vue'
import { ref , computed} from 'vue'


const tab = ref('DataPropsAndMethods')
const activeTab=computed(()=>({
    NavigationBar,
    TemplateSyntax,
    DataPropsAndMethods
}[tab.value]))


function changeTab (newTab) {
  tab.value = newTab
}
</script>

Upvotes: 3

tony19
tony19

Reputation: 138276

It seems with <script setup>, tab needs to reference the component definition itself instead of the component name.

To reference the component definition, which does not need reactivity, use markRaw() before setting tab.value:

<script setup>
import DataPropsAndMethods from './components/DataPropsAndMethods.vue'
import { ref, markRaw } from 'vue'

const tab = ref(null)

changeTab(DataPropsAndMethods)

// newTab: component definition (not a string)
function changeTab (newTab) {
  tab.value = markRaw(newTab)
}
</script>

demo 1

If you need to pass the component name to changeTab(), you could use a lookup:

<script setup>
import DataPropsAndMethods from './components/DataPropsAndMethods.vue'
import { ref, markRaw } from 'vue'

const tab = ref(null)

changeTab('DataPropsAndMethods')

// newTab: component name (string)
function changeTab (newTab) {
  const lookup = {
    DataPropsAndMethods,
    /* ...other component definitions */
  }
  tab.value = markRaw(lookup[newTab])
}
</script>

demo 2

Tested with Vue 3.0.9 setup with Vue CLI 5.0.0-alpha.8

Upvotes: 26

Related Questions