Vuex Store Tutorial: All you need to know about Vuex

Share This Post

The way of creating websites has changed a lot over the last decade. Currently, the trend is to use frameworks like React, Angular, or Vue. While each has its peculiarities, they all meet on the concept of component. A component is simply a self-contained part of your applications, typically made with HTML, CSS, and JS. An example of a component could be a pop-up message or a date picker. Since we use components to separate functionalities, sharing information among them can be hard. Fortunately, Vuex makes up for that. In this Vuex Store Tutorial, we will see how to use Vuex to share information among components.

Tip: this article requires at least basic knowledge of JavaScript and Vue.

The problem

Before we dive into the solution with our Vuex store tutorial, we better understand the problem. Components rely on information to do things, for example, a drop-down may be opened or closed based on the value of a variable. So far so good, but the real twist happens when many components work on the same variable. For example, the “Login” component updates the user data, and we want to see that data in the “Toolbar” component as well.

A quick solution is a top-down approach using v-bind. With this approach, the parent component passes information to the child component when declaring it. While this is a bidirectional binding for simple types, we might have problems with objects. Furthermore, we need to use it on all components between parent and child to maintain the chain. That’s not a real solution. Another option would be using busses, but that’s where things get really messy.

Vuex allows a better flow, based on actions, mutations, and state, as we will see. Here is a visualization of how Vuex approaches this problem.

Vuex Store Tutorial and how to manage the state of a complex Vue app.

Vuex Store Tutorial

Getting vuex

Vuex is a npm package like anything else in your Vue application. Thus, we can install it with the following command.

npm install vuex --save

Note the --save option, it will add vuex to your dependencies in your package.json. That’s important if you want to make your application portable and build on other devices. Besides installing vuex, this command might also set-up some sample files with a basic store, depending on the version.

Creating the Vuex Store

The first part of this Vuex Store tutorial is creating a store. A store is simply a container where you want to store your application data. Furthermore, this store is accessible natively in all your components, regardless of their location. In the end, the store is just a container of variables and functions to modify them. Let’s first create some variables.

Inside your src folder, create a new sub-folder named store. Here, we will put all the files that relate to our store. The first one will be index.js. Here, we can add the following code.

import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)

/* eslint-disable no-param-reassign */
export default new Vuex.Store({
  state: {
    userInformation: null,
    loggingIn: false
  }
})

After the imports, we tell our Vue engine to use Vuex. Then, we export a store that has two variables in its state: userInformation and loggingIn, with default values. We will use the first to store information about a logged user, and the second to toggle loadings in case the user is attempting to log in.

The next step in our vuex store tutorial is to include our store in the Vue application. This is done inside main.js. We add the import of the router (we don’t need to include the file name index.js because it is the index, just the folder will do). Then, we simply pass the store to our Vue app.

import store form './store'

new Vue({
  store,
  // existing Vue settings here...
}).mount('#app')   // or whatever mount point you have

Accessing the Vuex Store state from a component

Vue will “install” our Vuex Store inside its engine, and make it available to any component in our app. Thus, in our methods and computed properties of each component, we can access the state of the store in read-only. To access a state, simply use the following code.

let myVariable = this.$store.state.userInformation

Mutations

At this point in our vuex store tutorial, the store is still useless. This is because the variables inside the state are read-only from outside the store. To modify them, we have two options: mutations and actions. Mutations are the simplest ones, they allow sychronous modification. We can add them with the mutations object inside our store. Each mutation is a function that accepts a state as a parameter, and optionally a payload of information.

export default new Vuex.Store({
  state: {
    userInformation: null,
    loggingIn: false
  },
  mutations: {
    login (state, payload) {
      state.userInformation = payload
    },
    attemptLogin (state) {
      state.loggingIn = true
    },
    finishAttemptLogin (state) {
      state.loggingIn = false
    }
  }
})

To trigger a mutation from a component, you need to commit it. This can be done easily with the following code.

this.$store.commit('login', { name: 'John Doe' })
this.$store.commit('attemptLogin')

Actions

With actions, our vuex store tutorial becomes really interesting. They allow asynchronous modifications to the state. Yet, their structure is very similar to the mutations we have already seen. We add them in the actions object.

export default new Vuex.Store({
  state: {
  userInformation: null,
  loggingIn: false
  },
  mutations: {
    login (state, payload) {
      state.userInformation = payload
    },
    attemptLogin (state) {
      state.loggingIn = true
    },
    finishAttemptLogin (state) {
      state.loggingIn = false
    },
  },
  actions: {
    authenticate ({ commit }, { username, password }) {
      commit('attemptLogin')
      const data = new FormData()
      data.append('name', username)
      data.append('password', password)
      axios({
      method: 'post',
      url: '/my-authentication-url',
      data: data,
      config: { headers: { 'Content-Type': 'multipart/form-data' } }
      })
      .then(response => {
        if (response.status === 200) {
        commit('login', response.data)
        }
      })
      .then(function () {
        commit('finishAttemptLogin')
      })
    }
  }
})

Each action wants a commit as a first parameter. This is simply a callback to the commit function of this store. Then, it can optionally accept other parameters in a object (here we want to know username and password). Our authenticate function commits attemptLogin to indicate the user is logging in, then performs an asynchronous request to the server. If the request succeeds, it triggers the login mutation. In the end, it always triggers the finishAttemptLogin.

To call an action from a component you we use the dispatch function.

this.$store.dispatch('authenticate', { 'my-username', 'my-password' })

Getters

As we have already seen in our vuex store tutorial, state stores information. However, we might want to use some information that derives directly from the state. In other words, we might want to have computed properties in our vuex store as well. We can do that, and they are called getters. A getter is a function inside the getters object that wants the state as first parameter. Optionally, it can get the getters as the second parameter: this allows your function to rely on other getters as well.

export default new Vuex.Store({
  // State, mutations and actions (omitting for brevity) ...
  getters: {
    loggedIn: function (state) {
      return state.userdata !== null
    },
    userName: function (state, getters) {
      if (getters.loggedIn) {
        return state.userdata.name
      }
      return null
    }
  }
})

Now, we can access the getters anywhere in our component by using the getters property of the store.

let var1 = this.$store.getters.loggedIn
let var2 = this.$store.getters.userName

mapGetters & mapActions

Often times, we want to have a computed property in our component that returns the value of a getter in our state. On top of that, we might want to do the same with methods: a method that dispatches an action of our vuex store. Creating the method and calling the store action or getter is simply code redundancy, which is very bad. Luckily, Vuex comes with two methods that help us in this case.

With mapGetters, you can select a set of getters of your vuex store and install them as computed properties in your component. They will have the same name of the vuex getter. Use it as below.

import { <span class="hiddenSpellError" pre="import " data-mce-bogus="1">mapGetters</span> } from 'vuex'

export default {
  name: 'MyComponent',
  computed: {
    ...mapGetters([
      'loggedIn',
    'userName'
    ])
  }
}

The same is true with mapActions, but it is valid for methods instead of computed properties.

import { <span class="hiddenSpellError" pre="import " data-mce-bogus="1">mapActions</span> } from 'vuex'

export default {
  name: 'MyComponent',
  methods: {
    ...mapActions([
      'authenticate'
    ])
  }
}

Vuex store outside this.$store

So far in this vuex store tutorial, we have seen the magic of using this.$store property. However, this represents the Vue VM, and it means we can access it only from within components. What if we need to access the vuex store from outside a component? This is possible by importing the store. It won’t be a new instance, and use the same data in use inside your Vue VM.

import store from '../store'

let var = store.getters.loggedIn

Wrapping it up

In this vuex store tutorial, we have seen how to implement state management in vue. This is possible thanks to several great components like state, mutations, actions and getters. If you need more information, you can take a look at the official documentation. Instead, if you are in a hurry here we have a quick recap:

  • The state contains information, read-only from outside the store. Access the state object from any component with this.$store.state
  • Mutations allow you to change the value of the state synchronously, call them with this.$store.commit('mutationName', parameter)
  • Actions are similar to mutations, but they are asynchronous. Call them with this.$store.dispatch('actionName', parameter)
  • You can get computed properties of a store from the getters, with this.$store.getters.getterName
  • You can map getters and actions of your vuex store in a component with mapGetters and mapActions

What do you think of the Vuex store? Do you think you will have a better and cleaner code by using it? Let me know in the comments!

Picture of Alessandro Maggio

Alessandro Maggio

Project manager, critical-thinker, passionate about networking & coding. I believe that time is the most precious resource we have, and that technology can help us not to waste it. I founded ICTShore.com with the same principle: I share what I learn so that you get value from it faster than I did.
Picture of Alessandro Maggio

Alessandro Maggio

Project manager, critical-thinker, passionate about networking & coding. I believe that time is the most precious resource we have, and that technology can help us not to waste it. I founded ICTShore.com with the same principle: I share what I learn so that you get value from it faster than I did.

Alessandro Maggio

2019-04-25T16:30:25+00:00

Unspecified

Dev

Unspecified