Home > Enterprise >  Unable to mark Vue setup function as async
Unable to mark Vue setup function as async

Time:12-24

I have a Vue3 app using the composition api and want to fetch data asynchronously inside the setup function.

Approaches that worked for me:


Working with Promises

    <template>
      <div>{{ result }}</div>
    </template>
    
    <script lang="ts">
    import { defineComponent, ref } from "vue";
    
    export default defineComponent({
      setup() {
        const result = ref();
    
        fetch("https://api.publicapis.org/entries")
          .then((response: Response) => response.json())
          .then((jsonResponse: any) => {
            result.value = jsonResponse;
          });
    
        return { result };
      },
    });
    </script>

Working with the onMounted hook

    <template>
      <div>
        {{ result }}
      </div>
    </template>
    
    <script lang="ts">
    import { defineComponent, ref, onMounted } from "vue";
    
    export default defineComponent({
      setup() {
        const result = ref();
    
        onMounted(async () => {
          const response = await fetch("https://api.publicapis.org/entries");
          result.value = await response.json();
        });
    
        return { result };
      },
    });
    </script>

But I wasn't able to use async/await directly like so

    <template>
      <Suspense>
        <template #default>
          {{ result }}
        </template>
        <template #fallback> Loading... </template>
      </Suspense>
    </template>
    
    <script lang="ts">
    import { defineComponent, ref } from "vue";
    
    export default defineComponent({
      async setup() {
        const result = ref();
    
        const response = await fetch("https://api.publicapis.org/entries");
        result.value = await response.json();
    
        return { result };
      },
    });
    </script>

Based on this question

@vue-composition / How can I use asynchronous methods in setup()

and this linked article

https://vueschool.io/articles/vuejs-tutorials/suspense-new-feature-in-vue-3/

it should work.

The posted component is just the default Home.vue component rendered by the Vue router. So inside App.vue I'm using the tag <router-view /> and load the app with the home route.

How can I mark setup as async?

CodePudding user response:

First please be careful as Suspense is still experimental feature and can change any time...

In order to async setup to work, the component itself must be inside <suspense> ....your component is not inside <suspense> - it contains <suspense> component (which of course can not work until the component is created and that can happen only after your async setup resolves). You must place <suspense> as a child of <router-view> - see the docs

Here is a working demo (if you see import declarations may only appear at top level of a module first, just reload the right pane using the reload icon - seems like some glitch in the Matrix)

// App.vue
<router-view v-slot="{ Component }">
  <suspense timeout="0">
    <template #default>
      <component :is="Component"></component>
    </template>
    <template #fallback>
      <div>Loading...</div>
    </template>
  </suspense>
</router-view>
// Home.vue
<template>
  <div >
    <pre>{{ result }}</pre>
  </div>
</template>

<script>
import { defineComponent, ref } from "vue";

export default defineComponent({
  async setup() {
    const result = ref();

    const response = await fetch("https://api.publicapis.org/entries");
    result.value = await response.json();

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

Notice timeout="0" on suspense - it seems there is a timeout for switching to a "loading" state (probably to avoid too much screen flickering when async components resolve quickly enough)

A timeout prop can be specified - if a pending tree remains pending past the timeout threshold, the active tree will be unmounted and be replaced by the fallback tree.

I'm unable to find what is the default value for timeout right now. Feel free to tune it for your own needs...

  • Related