Using Vuex with the Vue Composition API

May 9th, 2020

While I was learning the Vue Composition API, something suddenly hit me. What about Vuex? How will I beautifully map my getters, mutations and actions like I currently do with the Options API?

Well, here are two ways to use Vuex with the new Vue Composition API.

Prefer screencasts? You'll find this and more over on the Vue Composition API course!

The store

To keep things simple, let's use a store that exists just to increment a number (pointless in reality).

export default new Vuex.Store({
    state: {
        counter: 0
    },

    getters: {
        counter (state) {
            return state.counter
        }
    },

    mutations: {
        SET_COUNTER (state, value) {
            state.counter = value
        }
    },

    actions: {
        incrementCounter ({ commit, state }, increment) {
            commit('SET_COUNTER', state.counter + increment)
        }
    }
})

No modules here, but the two methods we're going to look at both work with namespaced modules.

With our store defined, let's look at the two methods we can use to get Vuex hooked up in our components.

1. Access the store directly

This isn't everyone's cup of tea, but it works well for smaller components that don't use too many getters, mutations or actions.

import { computed } from '@vue/composition-api'

export default {
    setup (props, { root }) {
        const counter = computed(() => root.$store.getters.counter)

        function incrementCounter (increment) {
            root.$store.dispatch('incrementCounter', increment)
        }

        return {
            counter,
            incrementCounter
        }
    }
}

What's happening here:

  • We've destructured the context passed through as the second argument to setup, giving us access to the root Vue instance
  • The computed property counter gives us a reactive value for the current counter getter value
  • The incrementCounter function dispatches an action

This way, we can make use of the counter value and incrementCounter function in our component template.

<template>
    <div>
        {{ counter }} <a href="#" @click.prevent="incrementCounter(1)">Increment</a>
    </div>
</template>

2. Use the vuex-composition-helpers package

This'll feel more natural if you're used to working with mapGetters and mapActions in your components with the Options API.

The first thing you'll need to do is install the package.

Then, it's as simple as mapping getters, mutations, actions or state much like you're used to, using the functions provided.

import { useGetters, useActions } from 'vuex-composition-helpers';

export default {
    setup (props) {
        const { counter } = useGetters({
            counter: 'counter'
        })

        const { incrementCounter } = useActions({
            incrementCounter: 'incrementCounter'
        })

        return {
            counter,
            incrementCounter
        }
    }
}

The result in our template is exactly the same.

<template>
    <div>
        {{ counter }} <a href="#" @click.prevent="incrementCounter(1)">Increment</a>
    </div>
</template>

Out of habit, I'm passing objects through to the useGetters and useActions functions, but you can pass an array of items, too.

const { incrementCounter } = useActions(['incrementCounter'])

Once again, this will work with namespaced modules. As an example, if you had an auth module which contained authenticated and user getters, you'd do this.

const { authenticated, user } = useGetters({
    authenticated: 'auth/authenticated',
    user: 'auth/user',
})

Beautiful.

That's all

Nice. You have two solutions for using Vuex with the Composition API.

At the time of writing, Vue 3 hasn't officially been released, and Vuex may add support for this natively. I can't promise there won't be better solutions by the time you read this, but I doubt much will change.

Author
Alex Garrett-Smith

Comments

No coments, yet. Be the first to leave a comment.