Search code examples
vue.jsdomvue-componentrendering

Vue Component Renders Twice On Page


In my HomeView component I'm importing the AsideCTA component:

<template>
  <TheHero />
  <TheServices />
  <TheBundles />
  <AsideCTA title="Kontakta oss!" url="#">
    <p>
      Osäker på vad du behöver? Don't worry, vi hjälper dig!
    </p>
  </AsideCTA>
  <TheProcess />
  <ThePitch />
  <TheReferences />
  <AsideHook />
</template>

And in my AsideCTA component I'm importing the TheCTA component:

<script setup>
import TheCTA from './TheCTA.vue';
const props = defineProps(['title', 'url']);

</script>

<template>
  <aside class="aside-cta">
    <slot></slot>
    <TheCTA v-if="props.title" :url="props.url">{{ props.title }}</TheCTA>
  </aside>
</template>

TheCTA:

<script setup>
const props = defineProps(['url']);
</script>

<template>
  <a :href="props.url" class="cta"><slot></slot></a>
</template>

The problem is that the component renders along with another empty iteration, and I can't figure out why. I've tried to make the component conditional, but it still renders an empty element on the page with an empty v-if before it.

Without condition:

The component renders twice on the page

With condition:

<template>
  <AsideCTA v-if="asideCTATitle" :title="asideCTATitle" url="#">
    <p>
      Osäker på vad du behöver? Don't worry, vi hjälper dig!
    </p>
  </AsideCTA>
</template>

<script setup>
[...]

import { ref } from 'vue';

const asideCTATitle = ref(null);
</script>

Renders an empty element

Does anybody have a clue what's going on?


Solution

  • The problem can be visible in Vue devtools, rendered HomeView component contains:

    <AsideCTA ...>...</AsideCTA>
    <AsideCTA/>
    

    This means that it's not just a bug in DOM as the question shows, but the actual behaviour of HomeView. This is not possible under normal circumstances in Vue if there is only one AsideCTA in a template.

    The problem is caused by a typo:

    import AsideCTA from '../components/AsideCTA.vue';
    ...
    import TheProcess from '../components/AsideCTA.vue';
    

    This results in the second AsideCTA being rendered instead of TheProcess.