Possible for top level (App.vue) async setup?

Viewed 685

Is it possible to use await in the App.vue top component?

Whenever I try and use it, the app displays nothing?

<template>
    <Suspense>
        <template #default>
            <div>Hello</div>
        </template>
        <template #fallback>
            <div>Loading...</div>
        </template>
    </Suspense>
</template>

<script lang="ts">
import { defineComponent, onErrorCaptured, ref, Ref } from 'vue';
export default defineComponent({
    name: 'App',
    components: {},
    async setup() {
        console.log('async setup - App.vue');

        const error: Ref<undefined | Error> = ref(undefined);
        onErrorCaptured((e) => {
            error.value = e;
            return true;
        });
        if (error.value) return { error };

        return {};
    }
});
</script>

<style lang="scss">
</style>
2 Answers

When the setup() is async, the component itself becomes an async component. The component then must be rendered inside a <suspense> in the parent component. The <suspense> should not be in the async component's own template unless it has its own async component children.

<!-- Parent.vue -->
<template>
  <Suspense>
    <template #default>
      <MyAsyncComponent />
    </template>
    <template #fallback>
      <div>Loading...</div>
    </template>
  </Suspense>
</template>
<!-- MyAsynComponent.vue -->
<script>
import { defineComponent } from 'vue'

export default defineComponent({
  async setup() {
    ⋮
  }
})
</script>

If you did not intend to make the component async, and you only had async code to run in setup(), you should wrap that code in its own async block (e.g., in an async function). For example, it's common to fetch data upon mounting the component, so you could use an async callback to await the fetch call:

<!-- MyAsyncComponent -->
<script>
import { defineComponent, ref, onMounted } from 'vue'

export default defineComponent({
  setup() {
    const getPosts = async () => axios.get(⋯)
    const posts = ref([])

    onMounted(async () => {
      posts.value = await getPosts()
    })

    return { posts }
  }
})
</script>

I don't understand what is async about your app component judging from what you've provided but I'll share with you what I did, for my special need.

I have a module for application settings that exports a "load application settings" function. I wanted this object of appSettings to save state for things like: "is the side menu open or closed?" my module also exports 2 more function, one for providing getters and setters and one to inject it all. it's like a store without the store I guess.

So in order to load the data (from IndexedDB) before the creation of the app i've modified main.js like so:

import { createApp } from 'vue'
import { loadApplicationSettings } from '@/composables/useApplicationSettings';
    loadApplicationSettings()
        .then(() => {
            const app = createApp(App)
            app.mount('#app')
        });

now i've loaded some data into my module, and I can now use it in App.vue without the need to async App.vue, since that data is now stored in the module.

<script setup lang="ts">
import { initApplicationSettings } from '@/composables/useApplicationSettings';
initApplicationSettings();
</script>

so basically, in order to overcome 'App.vue can't do asnyc' I just get everything ready before I use createApp

hope this helps.

Related