Vue 3 defineAsyncComponent does not trigger onUpdated when mounting is done

368 Views Asked by At

In my Vue 3 application with Vite and Pinia I have a component that imports multiple accordion subcomponents. When all accordions are mounted, I get the list with querySelectorAll.

const Byg = defineAsyncComponent(() => import('@/components/bbrObject/entityType/Byg.vue')); // Includes a lot of .accordion-button elements

const accordionList = ref([]);

onUpdated(() => {
  accordionList.value = [].slice.call(document.querySelectorAll('.accordion-button')) as HTMLElement[];
  console.log(accordionList.value); // <-- Empty with async import
});

This works like a charm when I import my subcomponents directly, but as soon as I update my accordion subcomponents to be imported using defineAsyncComponent, onUpdated is still triggered but the accordionList remains empty.

My issue is that I can't find a way to know when my async components are done rendering, so I can access the DOM. I have tried adding watchers, used nextTick and even tried with a setTimeout. I also tried using the promise returned by defineAsyncComponent. I can't figure out a clean way to know when all async components are done loading.

I have set up an example of the issue: https://codesandbox.io/s/mystifying-morning-frqtlv?file=/src/App.vue

1

There are 1 best solutions below

3
On

The easiest way to detect when the async component is mounted is by explicitly emitting an event from it.

<!-- HelloWorld.vue -->
<script setup>
const emit = defineEmits<{
  (e: 'mounted'): void
}>()
onMounted(()=>{
  emit('mounted')
})
</script>

Then you can listen to the mounted event on your parent component

<!-- App.vue -->
<template>
  <HelloWorld @mounted="onAsyncMounted" msg="Hello Vue 3 in CodeSandbox!" />
</template>

<script setup>
const HelloWorld = defineAsyncComponent(() =>
  import("./components/HelloWorld.vue")
);

function onAsyncMounted() {
  // Now you can access DOM of the async component
}
</script>

Suspense provides a resolve event. But since it is still an experimental feature, I do not recommend using it.