Image

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

3 min read
Last update: December 19, 2021

App-wide Non-persisted State

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

In the size of the app we’re building, we could keep everything we need for email selection within the MailTable component… but by the end of the course, even in this simple app, it would get unwieldy. And if we expanded the app beyond just the mail table, we’d probably want access to the selected emails outside the table.

So we’re going to take this opportunity to learn a really useful pattern with the composition API - that of storing non-persisted app-wide state.

We’ll start with extracting to a composition function. We can use emails as the variable name for our reactive set because it no longer conflicts with the data from the server, but the rest of the function remains unchanged.

//In src/components/MailTable.vue
//...
import useEmailSelection from '@/composables/use-email-selection'

export default {
async setup(){
let {data: emails} = await axios.get('http://localhost:3000/emails')

return {
emailSelection: useEmailSelection(),
//...
}
}
}
//In src/composables/use-email-selection.js
import { reactive } from 'vue';

export const useEmailSelection = function(){
const emails = reactive(new Set());
const toggle = (email) => {
if(emails.has(email)) {
emails.delete(email)
} else {
emails.add(email);
}
};

return {
emails,
toggle
}
}

export default useEmailSelection;

Everything still works.

Now let’s use the composable in another component. We’ll choose App.vue, and just repeat the template display line.

<template>
    <h1>VMail Inbox</h1>

    <h1>{{emailSelection.emails.size}} emails selected</h1>

    <Suspense>
        <!-- ... -->
    </Suspense>
</template>

<script>
    import {
        useEmailSelection
    } from '@/composition/use-email-selection';
    //...

    export default {
        setup() {
            return {
                emailSelection: useEmailSelection()
            }
        }
        //...
    }
</script>

Now you’ll notice an issue… when you check a box, it updates the size of the email Set displayed in MailTable.vue, but not in App.vue.

Why?

Because a new Set has been created for each usage of useEmailSelection. It’s not a global state.

We can make it a global state by instantiating the Set outside the function call.

let emailSet = new Set()

export const useEmailSelection = function(){
const emails = reactive(emailSet);
//...

return {
emails,
//...
}
}

Now we can have app-wide non-persisted state, but in a way that’s well-defined and easy for future developers to understand.

You might also notice that this is something that’s usually done with Vuex, and did it in a way that appears to be scalable. How much Vuex usage will Composition API be replacing? It remains to be seen, but my guess is that newer versions of Vuex will take advantage of the Composition API to create an experience that’s even smoother and more scalable than just using the Composition API or the old Vuex patterns on their own.

In the next lesson we’ll adding a Select All checkbox, which will select and unselect all the emails, as well as reflect the status of individually selected emails. I’ll see you then.

For the ending code for this lesson, switch to branch: https://github.com/Code-Pop/build-gmail-clone-with-vue-3/tree/video-12-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.