Vue.js 3 Composition API Vuex Tutorial

In this Vue tutorial we learn how Vuex works with the Composition API.

We cover how to create a reference to the store to interact with it.

Lesson Video

If you prefer to learn visually, you can watch this lesson in video format.

Lesson Project

If you want to follow along with the examples in this lesson, you will need an app generated by the Vue CLI with the Vuex package installed .

The project should look similar to the following.

Example: project
project-name/
├── src/
|   ├── main.js
|   └── App.vue

To keep things simple, we will hold the entire Vuex store in the main.js file and the functionality in the root App component.

The store has a counter property that can be returned with a getter. We use a mutation that can accept a payload to increment the counter and an action to commit the mutation.

Example: src/main.js
import { createApp   } from 'vue'
import { createStore } from 'vuex'
import App from './App.vue'

const store = createStore({
  state() {
    return {
      counter: 0
    }
  },
  getters: {
    getCounter(state) { return state.counter }
  },
  mutations: {
    increment(state, payload) {
      state.counter = state.counter + payload
    }
  },
  actions: {
    increment(context, payload) {
      context.commit('increment', payload);
    }
  }
})

const app = createApp(App)

app.use(store)
app.mount('#app')

In the root App component, we have a button that refers to the incrementCounter method that dispatches the increment action. We also track and output the counter property with the trackCounter computed property.

Example: src/App.vue
<template>
  <p>Counter: {{ trackCounter }}</p>
  <button @click="incrementCounter">Increment</button>
</template>

<script>
export default {
  methods: {
    incrementCounter() {
      this.$store.dispatch('increment', 1)
    }
  },
  computed: {
    trackCounter() {
      return this.$store.getters.getCounter
    }
  }
}
</script>

If we run the example in the browser and click the button, the counter value should increase by 1.

Vuex with the Composition API

When we refer to the store in the Options API, we use the special this.$store instance variable.

To get that reference in the Composition API, Vuex gives us the useStore method that we import and assign to a constant in the setup method.

Syntax: useStore
<script>
import { useStore } from 'vuex'

export default {
  setup() {
    // get a reference to
    // the store in main.js
    const store = useStore()
  }
}
</script>

Once we have the reference, we can replace all instances of this.$store in our code with it. Everything else about Vuex works the same, it’s just our reference that changes.

To demonstrate, we’ll convert our example to use the Composition API.

1. We’ll start by replacing the methods option with setup . Inside, we’ll define the incrementCounter method using the store reference to dispatch the increment action.

Then, we’ll bind it to the button’s click event in the template.

Example: src/App.vue
<template>
  <p>Counter: {{ trackCounter }}</p>
  <button @click="incrementCounter">Increment</button>
</template>

<script>
import { useStore } from 'vuex'

export default {
  setup() {
    // new store reference
    const store = useStore()

    function incrementCounter() {
      // replace 'this.$store' with
      // the new 'store' reference
      store.dispatch('increment', 1)
    }

    return {
      incrementCounter
    }
  },
  computed: {
    trackCounter() {
      return this.$store.getters.getCounter
    }
  }
}
</script>

2. For the computed property, we’ll import and use the computed method with an arrow function that returns the getCounter getter.

Example: src/App.vue (trackCounter)
<template>
  <p>Counter: {{ trackCounter }}</p>
  <button @click="incrementCounter">Increment</button>
</template>

<script>
import { computed } from 'vue'
import { useStore } from 'vuex'

export default {
  setup() {
    const store = useStore()

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

    const trackCounter = computed(() => {
      return store.getters.getCounter
    })

    return {
      trackCounter,
      incrementCounter
    }
  }
}
</script>

If we run the example in the browser, everything still works as expected and the counter increments by 1.

Further Reading

For more information on the topics covered in this lesson, please see the relevant sections below.