Home > Mobile >  Render dynamic components in Vue3
Render dynamic components in Vue3

Time:11-04

Im trying to render my components based on the "__typename" in my API response:

{
  "data": {
    "home": {
      "data": {
        "attributes": {
          "webcomponents": [
            {
              "__typename": "ComponentWebComponentsFooterWidget"
            },
            {
              "__typename": "ComponentWebComponentsImage"
            },
            {
              "__typename": "ComponentWebComponentsImageText",
              "title": "test",
            }
          ]
        }
      }
    }
  }
}

But nothing gets rendered. This is my vue3 code:

<script setup>
import { defineAsyncComponent, ref } from 'vue'
import { useHomeQuery } from '@/generated/operations'

const ComponentWebComponentsFooterWidget = defineAsyncComponent(() =>
  import('../components/Hero1.vue'),
)
const ComponentWebComponentsImage = defineAsyncComponent(() =>
  import('../components/Hero2.vue'),
)
const ComponentWebComponentsImageText = defineAsyncComponent(() =>
  import('../components/Hero3.vue'),
)
const { result, loading: queryLoading, error } = useHomeQuery({})
</script>

<template>
  <div v-for="item in result.home.data.attributes.webcomponents" :key="item.id">
    <component :is="item.__typename" />
  </div>
</template>

I get it to work as expected in vue2, but im quite new to vue3.

CodePudding user response:

In Vue 3 with script setup <component :is /> needs a reference to the component definition instead of a component name as a string.

Try this:

<script setup>
// ...
const componentMap = {
  ComponentWebComponentsImage: defineAsyncComponent(() =>
    import('../components/Hero1.vue'),
  ),
  ComponentWebComponentsImage: defineAsyncComponent(() =>
    import('../components/Hero2.vue'),
  ),
  ComponentWebComponentsImageText = defineAsyncComponent(() =>
    import('../components/Hero3.vue'),
  )
}
</script>

<template>
  <div v-for="item in result.home.data.attributes.webcomponents" :key="item.id">
    <component :is="componentMap[item.__typename]" />
  </div>
</template>
  • Related