Image

build-a-gmail-clone-with-vue-3

3 min read
Last update: December 19, 2021

Async Setup & Suspense

For the starting code for this lesson, switch to branch: https://github.com/Code-Pop/build-gmail-clone-with-vue-3/tree/video-3-start

Making Data Dynamic

In this lesson and the next, our goal is to make our data dynamic, pulling it from a server and saving any changes back to the server.

To do that we’re going to learn about the setup method and the Suspense component in this video, and axios and json-server in the next.


The Setup Function

Using async/await doesn’t work with the data function, so let’s switch to the setup function.

setup(){
let emails = [...]
return {
format,
emails
}
}

At its most basic form, it works like the data function. Notice that we can use the setup function (part of the composition API) and computed properties hash (part of the options API) in the same component at the same time!

When we try to make it async , instead of an error in shows a blank screen and the following warning: async setup() is used without a suspense boundary! at <App> (Root).


The Suspense Component

The Suspense component has two slots: default and fallback.

Within the default slot, we put a component that can load asynchronously.

Within the fallback slot, we put what we want displayed while the async loading hasn’t yet completed.

<Suspense>
<template #default>
    <!-- Main thing to show -->
    <MailTable />
</template>
<template #fallback>
    <!-- What to show while it's loading -->
    Loading...
</template>
</Suspens>

In this case, we’re pulling our table to the MailTable component and then putting that component in the default slot.


The MailTable Component

This is what our App.vue looks like after extracting the MailTable component.

<template>
    <div id="app">
        <h1>VMail Inbox</h1>

        <MailTable />
    </div>
</template>

<script>
    import MailTable from '@/components/MailTable.vue';

    export default {
        name: 'App',
        components: {
            MailTable
        }
    };
</script>

And here’s what the MailTable component looks like.

<template>
    <table class="mail-table">
        <tbody>
            <tr v-for="email in unarchivedEmails" :key="email.id" :class="['clickable', email.read ? 'read' : '']" @click="email.read = true">
                <td>
                    <input type="checkbox" />
                </td>
                <td>{{email.from}}</td>
                <td>
                    <p><strong>{{email.subject}}</strong> - {{email.body}}</p>
                </td>
                <td class="date">{{format(new Date(email.sentAt), 'MMM do yyyy')}}</td>
                <td><button @click="email.archived = true">Archive</button></td>
            </tr>
        </tbody>
    </table>
</template>

<script>
    import {
        format
    } from 'date-fns';

    export default {
        async setup() {
            return {
                format,
                data: [ /* ... */ ]
            }
        },
        computed: {
            sortedEmails() {
                return this.emails.sort((e1, e2) => {
                    return e1.sentAt < e2.sentAt ? 1 : -1
                })
            },
            unarchivedEmails() {
                return this.sortedEmails.filter(e => !e.archived)
            }
        }
    }
</script>

Async setup

You may be noticing that Loading... isn’t ever showing… that’s because we’re not yet using our async setup to its fullest.

In the next lesson, we’re going to use Axios and json-server, but for now let’s just make a delay for the sake of the demonstration:

async setup(){
await new Promise(resolve => setTimeout(resolve, 3000));

return {
format,
emails: [/* ... */]
}
},

We’ll see the nice Loading... message for 3 seconds, then the emails.

For the ending code for this lesson, switch to branch: https://github.com/Code-Pop/build-gmail-clone-with-vue-3/tree/video-3-end

Jeffrey teaches an 8-week beginning Vue course with guaranteed results. Built on top of the VueMastery curriculum, with extra hands-on assignments and personal attention. You can find it here.