Search code examples
vue.jsquasargun

Asynchronously modify value of component in Quasar


I am trying to modify the alias field when a promise is resolved. When I try to await the promise, Quasar errors out with:

[Vue warn]: Component <MainLayout>: setup function returned a promise, but no <Suspense> 
boundary was found in the parent component tree. A component with async setup() must be 
nested in a <Suspense> in order to be rendered. 

I tried wrapping everything in the <Suspense> tag including the individual spot I'm awaiting that data, but I still get this error.

I'm trying to promisify a GUN DB event that resolves a user's alias by pubkey.

<template>
  <Suspense>
    <q-layout view="lHh Lpr lFf">
      <q-header elevated>
        <q-toolbar>
          <q-btn
            flat
            dense
            round
            icon="menu"
            aria-label="Menu"
            @click="toggleLeftDrawer"
          />

          <q-toolbar-title> Quasar App </q-toolbar-title>

          <div>{{ alias }}</div>
        </q-toolbar>
      </q-header>

      <q-drawer v-model="leftDrawerOpen" show-if-above bordered>
        <q-list>
          <q-item-label header> Essential Links </q-item-label>

          <EssentialLink
            v-for="link in essentialLinks"
            :key="link.title"
            v-bind="link"
          />
        </q-list>
      </q-drawer>

      <q-page-container>
        <router-view />
      </q-page-container>
    </q-layout>
  </Suspense>
</template>

<script>
import { defineComponent, ref } from "vue";
import EssentialLink from "components/EssentialLink.vue";

import { GUN } from "boot/gun";

const gun = Gun();
const user = gun.user().recall({ sessionStorage: true });

const linksList = [
  {
    title: "Docs",
    caption: "quasar.dev",
    icon: "school",
    link: "https://quasar.dev",
  },
];

export default defineComponent({
  name: "MainLayout",

  components: {
    EssentialLink,
  },

  async setup() {
    const leftDrawerOpen = ref(false);

    let alias = "Getting alias";
    const pubkey = JSON.parse(sessionStorage.getItem("pair")).pub;

    alias = new Promise((resolve, reject) => {
      gun.user(pubkey).once((data) => resolve(data.alias));
    });

    return {
      alias,
      essentialLinks: linksList,
      leftDrawerOpen,
      toggleLeftDrawer() {
        leftDrawerOpen.value = !leftDrawerOpen.value;
      },
    };
  },
});
</script>

What is the proper way to await this data and update it in Quasar?


Solution

  • You could move the async operation to the mounted hook. Also, because you want alias to reactively update on the UI you should wrap it in a ref() when initializing. I've provided simplified code below showing how it can be done:

    <template>
      <div>{{ alias }}</div>
    </template>
    
    <script>
    import { defineComponent, ref } from "vue";
    
    export default defineComponent({
      setup() {
        const alias = ref("Getting alias");
    
        return {
          alias,
        };
      },
      async mounted() {
        this.alias = await new Promise((resolve, reject) => {
          gun.user(pubkey).once((data) => resolve(data.alias));
        });
      },
    });
    </script>
    

    example codesandbox