Can you explain how to incorporate async/await within the setup() function of Vue 3.0 using Typescript?

(This particular inquiry pertains to TypeScript, not JavaScript. Despite a resolved JavaScript query below, this issue remains specific to TypeScript).

I am attempting to implement async functionality in Vue 3.0 using TypeScript.

The following code operates effectively without async:

// file: components/HelloWorld.vue

<template>
  <div class="hello">
    <h1>{{ msg }}</h1>
  </div>
</template>

<script lang="ts">
import {defineComponent} from 'vue'

export default defineComponent({
  name: 'HelloWorld',
  props: {
    msg: String,
  },
  async setup() { // <-- works fine without 'async'
    const test = 'test'

    // await doSomethingAsynchronous()

    return {
      test,
    }
  },
})
</script>

Upon implementing async setup(), the element "HelloWorld" vanishes from the page, accompanied by an error message within the Firefox console:

"Uncaught (in promise) TypeError: node is null (runtime-dom.esm-bundler.js)"

Transitioning async setup() to setup() allows the code to function properly, albeit inhibiting async/await usage within the setup function.

Therefore, my inquiry revolves around utilizing async/await within the setup() function while employing TypeScript.

UPDATE:

A response regarding the question posed at why i got blank when use async setup() in Vue3 demonstrates that async setup() functions adequately with JavaScript, suggesting it should similarly work seamlessly with TypeScript as well.

Answer №1

Utilize the onMounted hook for handling asynchronous calls like this:

 setup() {
    const users = ref([]);
    onMounted(async () => {
      const res = await axios.get("https://jsonplaceholder.typicode.com/users");
      users.value = res.data;
      console.log(res);
    });

    return {
      users,
    };
  },

LIVE DEMO

As mentioned in the official documentation, the recommended approach is to use async setup in the child component and wrap it with a Suspense component in the parent component:

UserList.vue

<script lang="ts">
import { defineComponent } from "vue";
export default defineComponent({
    async setup() {
        //fetch users from jsonplacerholder using await fetch api
        const users = await fetch("https://jsonplaceholder.typicode.com/users").then(res => res.json());

        return {
            users
        }
    }
})
</script>
<template>
    <div>
        <!-- list users -->
        <ul>
            <li v-for="user in users">{{ user.name }}</li>
        </ul>
    </div>
</template>

Parent component:

<script lang="ts">

import UserList from "../components/tmp/UserList.vue";
...
</script>

   <div>
            <!-- Suspense component  to show users  -->
            <Suspense>
                <template #fallback>
                    <div>loading</div>
                </template>

                <UserList />
            </Suspense>
        </div>

Answer №2

A different approach to accomplish this task:

 let userList = ref([]);

 (async () => {
   const response = await axios.get("https://jsonplaceholder.typicode.com/users");
   userList.value = response.data;
   console.log(response);
 })()

 return {
   userList,
 }

You don't need to wait for it to mount, similar to utilizing created() in the options API.

Note: Always remember to end a statement with a semicolon ";" before declaring a function; otherwise, JavaScript might misinterpret it as the previous statement intending to return a function. For instance, missing the semicolon could lead to the bug "ref([]) is not a function":

const userList = ref([]) // Missing semicolon here

(async () => {

To prevent this issue, another effective practice is placing the semicolon on the same line as the function definition, like so:

;(async () => {

Answer №3

If you want to invoke the API even before the beforeCreate() lifecycle hook, there are a few approaches you can take:

  1. Utilize a helper function (which is more elegant than using ;(async () => {})()):
// utils.ts
export const run = (asyncFn: () => Promise<void>) => asyncFn()
// component.vue
<script lang="ts" setup>
  import { ref } from 'vue'
  import { run } from './utils.ts'
  import { getUsers } from './api.ts'

  const users = ref([])

  run(async () => {
    // getUsers() will be called before beforeCreate()
    users.value = await getUsers()
    // ...
  })
</script>
  1. Employ promise chaining method:
// component.vue
<script lang="ts" setup>
  import { ref } from 'vue'
  import { getUsers } from './api.ts'

  const users = ref([])

  // getUsers() will be called before beforeCreate()
  getUsers().then(users => {
    users.value = users
    // ...
  })
</script>

Answer №4

Here is an alternative approach. It bears resemblance to gustavodacrvi's solution. However, if you are not a fan of self-invoking functions like myself, you may appreciate this version more:

<script setup lang="ts">
const users = ref<User[]>([])
const isLoading = ref(true)

async function fetchUsers() {
  users.value = await getUsers()
  isLoading.value = false
}

fetchUsers()
</script>

This implementation takes the loading state into consideration, as the users array starts empty and then gets populated.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Angular is experiencing difficulty locating the routing path for the auxiliary `router-outlet`

Exploring the intricacies of routing in Angular to gain a deeper understanding of the concept. Encountering an issue where I am receiving an exception NG04002: Cannot match any routes. URL Segment: 'about' when attempting to click on the About li ...

``Can someone provide guidance on how to showcase the validation check result for a text-field in the snackbar using Vuet

One of the challenges I'm facing in my project is implementing a validation function for the customer form. While using the vuetify validate method would be the easy way to go, I need to display the validation messages both as snackbar and next to eac ...

What is the reason behind the absence of compile time errors when using 'string' functions on an 'any' field type variable in TypeScript?

Looking at the following typescript code snippet: let a; a = "number"; let t = a.endsWith('r'); console.log(t); It is worth noting that since variable 'a' is not declared with a specific type, the compiler infers it as ...

What is the best way to incorporate Twitter Bootstrap CSS and Javascript into a basic VueJS project?

vue init webpack helloworld npm run dev I am thrilled to have a new Vue project. I am wondering how I can seamlessly incorporate the latest version of Twitter Bootstrap into my project, both CSS and Javascript. I attempted to install it using NPM and re ...

Is it possible for Typescript to utilize Webpack's UMD feature for importing

Is there a method in TypeScript to import a module wrapped by webpack UMD (Universal Module Definition)? For instance: npm install knockback The file .js (node_modules/knockback/knockback.js) starts like this: (function webpackUniversalModuleDefinition( ...

The readline interface in Node that echoes each character multiple times

After creating a node readline interface for my project, I encountered an unusual issue. this.io = readline.createInterface({ input: process.stdin, output: process.stdout, completer:(line:string) => { //adapted from Node docs ...

Angular Material: Enhanced search input with a universal clear button

After searching for a cross-browser search control with a clear button similar to HTML5, I found the solution rendered by Chrome: <input type="search> The code that gave me the most relevant results can be found here. I used the standard sample w ...

What is the role of authguard in securing routes?

When developing an application, I encountered the need to implement authorization to protect routes using AuthGuard. However, I now face the challenge of securing child routes based on a role system obtained from the backend during login. For example, if t ...

Oops! Looks like the code encountered an error: Home is not defined in Laravel Vue.js

I am embarking on my journey with Vue and Laravel, aiming to create a seamless single page application. Even though I have set up my router and routes, an error pops up stating that my component is not defined. It's puzzling because I do have a Home c ...

What causes the v-for in a template to only update when the input text changes?

I'm currently working on a Vue.js code, but I'm facing an issue where the template isn't updating when new data is added to the input text. My goal is for the list to update when the @click event occurs. Visit this link for reference metho ...

Perform a child component function in Angular

I'm working on a project with a child component as a map and a parent component as a form. The parent component has a field for writing the address, and when an address is entered, an HTTP request is triggered to find the latitude and longitude coordi ...

What is the best way to organize my NPM package with separate directories for types and functions?

I am currently working on developing a custom NPM package that will serve as a repository for sharing types and functions across my project. Let's name this project wordle. Given the emphasis on types, it is worth noting that I am using TypeScript for ...

Importing ES Module is a requirement when making updates to Angular framework

During the process of upgrading from Angular 6 to 8, I encountered a frustrating issue. Every time I attempt to run 'ng serve' or 'ng build', I encounter the following error: I have tried various solutions such as adding "type":"module ...

Vue - Additional loading may be required to manage the output of these loaders

Currently working with Vue and babel. I have a function that's been exported // Inside file a.js export async function get() { ... } I am trying to link this exported function to a static method of MyClass // Inside file b.js import myInterface fr ...

unable to establish initial boundaries for vuemapbox map

I am currently utilizing mapbox-gl and vue-mapbox within my Vue.js application to showcase a map. My goal is to set the initial boundaries of the map to encompass the continental US, and upon loading, zoom in on a specific location within the country. Whe ...

Tips for resolving the error: finding the right loader for handling specific file types in React hooks

data = [{ img: '01d' }, { img: '02d' }] data && data.map((item) => ( <img src={require(`./icons/${item['img']}.svg`).default} /> )) I am facing an issue with the message Error: Module parse failed: U ...

Typescript inheritance results in an undefined value being returned

I am trying to understand the code below, as I am confused about its functionality. In languages like C# or Java, using the base or super keyword usually returns values, whereas in TypeScript, I am receiving "undefined". However, when I switch from using " ...

Angular 5 encountering issue with @Injectable annotation causing TypeScript error

While trying to compile my code, I encountered the following error: import { HttpClient } from '@angular/common/http'; import { Injectable } from '@angular/core'; @Injectable() export class TaskService { constructor(private http: Ht ...

Encountered error code 422 Unprocessable_entity upon submitting form to Rails API via Vue.js application

Currently, I am in the process of developing an application using Rails 6 Api as a backend and Vue as a standalone web app. After successfully setting up my sign-up form, I encountered a frustrating issue upon submission where I received a Completed 422 U ...

Displaying nested web service array data in Angular 4

I created a project that retrieves data from a web service API. However, the API contains nested arrays that also need to be displayed. How can I access the data from these nested JSON arrays? What is the correct way to extract this data within the HTML co ...