Setting up Vuex (state management) with Vue CLI 3
Tags: vue, vuex, statemanagement
Published: 2020-03-07 11:04:33

> This article explains how to set up `Vuex` in a Vue CLI 3 project. It is really helpful while you are managing user's state when authenticating a Vue application.

Steps to follow -

- [Install Vuex](#install)
- [Add Vuex to your application](#add-vuex-to-your-application)
- [Creating store object and usage](#creating-store-object)
- [Extracting store into individual file](#extracting-store)
- [Using Vuex modules](#using-vuex-modules)

<a name="install"></a>

## Install Vuex

First step is to install Vuex via npm or yarn

```bash
# Using npm
npm install vuex --save

# Using Yarn
yarn add vuex
```

<a name="add-vuex-to-your-application"></a>

## Add Vuex to your application

When used with a module system, you must explicitly install Vuex via `Vue.use()`

```js
//main.js
import Vue from "vue";
import Vuex from "vuex";

Vue.use(Vuex);
```

<a name="creating-store-object"></a>

## Creating store object to use in Vue App

After installing Vuex, let's create a store. It is pretty straightforward - just provide an initial state object, and some mutations:

```js
//main.js
// Make sure to call Vue.use(Vuex) first if using a module system
const store = new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment(state) {
      state.count++;
    }
  }
});
// Make sure to inject the store in the vue instance
new Vue({
  store,
  render: h => h(App)
}).$mount("#app");
```

---

> Due to using a single state tree, all state of our application is contained inside one big object. However, as our application grows in scale, the store can get really bloated.

Vuex allows us to divide our store into modules. Each module can contain its own state, mutations, actions, getters, and even nested modules. For any reference, please [checkout this guide](https://vuex.vuejs.org/guide/modules.html)
<a name="extracting-store"></a>

## Extracting store into individual file

Now create a `index.js` file in `src/store/index.js` and add

```js
//index.js
import Vue from "vue";
import Vuex from "vuex";

Vue.use(Vuex);

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

  getters: {
    errors(state) {
      return state.errors;
    }
  },

  mutations: {
    SET_ERRORS(state, data) {
      state.errors = data;
    }
  },

  actions: {
    setErrors({ commit }, errors) {
      commit("SET_ERRORS", errors);
    }
  }
});
```

<a name="using-vuex-modules"></a>

## Using vuex modules

Our updated `index.js` file will look like

```js
//index.js
import Vue from "vue";
import Vuex from "vuex";

// importing a vuex module
// imporing the auth module which handles the user authentication
import auth from "./auth";

Vue.use(Vuex);

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

  getters: {
    errors(state) {
      return state.errors;
    }
  },

  mutations: {
    SET_ERRORS(state, data) {
      state.errors = data;
    }
  },

  actions: {
    setErrors({ commit }, errors) {
      commit("SET_ERRORS", errors);
    }
  },
  modules: {
    //registering the auth module that is imported
    auth
  }
});
```

This blog post example uses `graphql` client for autenticating the users. If you are using `axios` as a http client, then your `vuex actions` might look different than this. The `auth.js` file will look like

```js
//auth.js
import {
  LOGIN_USER_MUTATION,
  GET_CURRENT_USER,
  LOGOUT
} from "../graphql/queries/userQueries";
import { Apollo } from "../graphql/apollo";

export default {
  namespaced: true,
  state: {
    token: null,
    user: null
  },
  getters: {
    authenticated(state) {
      return !!state.token && !!state.user;
    },
    user(state) {
      return state.user;
    }
  },
  mutations: {
    SET_TOKEN(state, token) {
      state.token = token;
    },
    SET_USER(state, data) {
      state.user = data;
    }
  },
  actions: {
    async login({ dispatch }, credentials) {
      let response = await Apollo.mutate({
        mutation: LOGIN_USER_MUTATION,
        variables: {
          username: credentials.email,
          password: credentials.password
        }
      });

      return dispatch("attempt", response.data.login.access_token);
    },
    async attempt({ commit, state }, token) {
      if (token) {
        localStorage.setItem("token", token);
        commit("SET_TOKEN", token);
      }
      if (!state.token) {
        return;
      }
      try {
        let response = await Apollo.query({
          query: GET_CURRENT_USER
        });
        commit("SET_USER", response.data.me);
        Apollo.resetStore();
      } catch (e) {
        localStorage.removeItem("token");
        commit("SET_TOKEN", null);
        commit("SET_USER", null);
        Apollo.resetStore();
      }
    },

    logout({ commit }) {
      return Apollo.mutate({
        mutation: LOGOUT
      }).then(() => {
        // console.log(store);
        localStorage.removeItem("token");
        commit("SET_TOKEN", null);
        commit("SET_USER", null);
        Apollo.resetStore();
      });
    }
  }
};
```

## Import the file in your Vue app(main.js)

Now our updated `main.js` file will look like

```js
//main.js
import Vue from "vue";
//import the store module
import store from "@/store";

// Make sure to inject the store in the vue instance
new Vue({
  store,
  render: h => h(App)
}).$mount("#app");
```

That’s it! Now restart your Vue CLI project and it should all work fine. Checkout Official [Vuex](https://vuex.vuejs.org/) docs for more information.