# Migrating A VueJS App To Vuex

##### Anthony Gore | August 14th, 2017 | 5 min read

[vue.js](/content/topics/vue-js/index.html) [vuex](/content/topics/vuex/index.html)

* * *

One of the difficult things about getting started with Vuex is that it is not so much a _library_ as it is a _design pattern_. It follows that implementing Vuex is not so much about using an API, as it is about structuring your code to comply with the pattern. If you're new to Vuex, this will be daunting.

In this article, I'll demonstrate how to get started migrating Vuex into an existing Vue.js project. I'll show you how to identify the parts of your app's state that belong in Vuex, and those that don't, how to refactor your component functions into mutations, actions and so on, and finally we'll discuss the benefits accrued.

> If you're not sure why you should use Vuex, I recommend you read this post first [WTF Is Vuex: A Beginner’s Guide to Vue’s Application Data Store](/content/2017/05/15/vue-js-what-is-vuex/index.html).

## Case study: Vue.js Cinema

As a case study, we'll migrate a demonstration app I made called [Vue.js Cinema](http://vuejs-cinema.vuejsdevelopers.com/) to Vuex. It's a single-file component-based Vue app that is a good enough candidate for Vuex as it has a significant amount of application state.

> If you want to learn how to build Vue.js Cinema from scratch, it's part of my [Ultimate Vue.js Developers course](https://www.udemy.com/vuejs-2-essentials/?couponCode=VUEJS-BLOG).

Remember that Vuex's purpose is to manage application state. It follows that in order to migrate Vue.js Cinema to Vuex, we must identify its state. We'll see the state in the code shortly, but it's helpful to first infer it by simply observing what the app does i.e. it displays a list of movies and session times that can be filtered by changing the day, or toggling time and genre filters.

## What state belongs in Vuex?

By using Vue Devtools, or just inspecting the code, we can see the data of the instance and each component:

Our objective is not to move all data to the Vuex store. Instead, we want to target data which:

1. Changes throughout the lifecycle of the application (static data doesn't need much management).
2. Is shared by more than one instance/component.

We when say _application state_, this is what we're talking about, and this is what we want to move into the store.

For example, look at this bank of `check-filter` components, which are custom checkboxes used to filter the movie list:

Each `check-filter` component has a `checked` data property, and also a title that is passed to it as a prop e.g. _Before 6pm_, _After 6pm_ etc:

_src/components/CheckFilter.vue_

```html
<template>...</template>
<script>
  export default {
    data() {
      return {
        checked: false
      }
    },
    props: [ 'title' ],
    ...
  }
</script>
```

The _checked_ data property is text-book application state, as it changes throughout the lifecycle of the app, and other components will certainly need to react to its state.

The _title_ prop, on the other hand, does not change, and does not affect any other component. It therefore does not need to be managed by Vuex.

> Note: if you have any local state that's important enough that you want to track it in devtools, then it is fine to add it to the Vuex store; it's not a violation of the pattern.

## Props → State

If you've modularised your application into components, as I have with Vue.js Cinema, a good place to start looking for application state is your component props, and more specifically, props across multiple components that share the same data.

For example, I bound the data property `day` from the root instance of this application to the _day-select_ and _movie-list_ components. The day select is how a user selects what day of the week they want to see session times for, and the movie list is filtered by the selected value.

_The day-select component_

To manage `day` in Vuex we can simply delete it from the root instance and move it to the `state` object in the Vuex store:

```
export default new Vuex.store({
  state: {
    day: moment() // the initial value
  },
  ...
});
```

We can then delete the binding from the template i.e. `v-bind:day="day"`, and in the component, replace the prop with a computed property that calls the store. In the case of _day-select_:

```js
export default {
  props: [ 'day' ],
  ...
}
```

Goes to:

```js
export default {
  computed: {
    day() {
      return this.$store.state.day
    }
  }
}
```

## Events → Mutations

While props are about sharing data across components, events intend to change it. The event listeners in your code should be considered for conversion to Vuex mutations. Event emitters will then be refactored to commit a mutation, rather than emit an event.

To return to the example of the _day-select_ component, whenever a user changes the day by clicking the appropriate piece of UI, this component method is called:

```
selectDay(day) {
  this.$emit('setDay', day);
}
```

The root instance has a listener to respond to the custom `setDay` event:

```
created() {
  this.$on('setDay', day => { this.day = day; });
}
```

In the case of the listener, it can be transferred from the root instance and put into the _mutations_ object of the store with only slight modification:

_src/store/index.js_

```js
export default new Vuex.Store({
  state: {
    day: moment()
  },
  mutations: {
    setDay(state, day) {
      state.day = day;
    }
  }
});
```

A mutation commit will now replace the event emit in the _day-select_ component:

```
selectDay(day) {
  this.$store.commit('setDay', day);
}
```

We can now remove the event listener binding in the template as well i.e. `v-on:click="setDay"`.

## AJAX → Actions

Actions in Vuex are the mechanism for handling asynchronous mutations. If you're using AJAX to update your application state, you'll probably want to wrap it in an action.

In Vue.js Cinema, I use AJAX (via the Vue Resource HTTP client) to populate the movie data from an API endpoint on my server:

_src/main.js_

```js
created() {
  this.$http.get('/api').then(response => {
    this.movies = response.data;
  });
}
```

This only happens once in the application lifecycle, when it is created, so it does seem somewhat trivial to log this with Vuex, but there's no harm, and still a lot to gain in terms of debugging.

Actions are dispatched from the application and must commit a mutation once the asynchronous event completes. Here's the code to add to the store:

_src/store/index.js_

```js
export default new Vuex.Store({
  state: {
    ...
    movies: []
  },
  mutations: {
    ...
    setMovies(state, movies) {
      state.movies = movies;
    }
  },
  actions: {
    getMovies({ commit }) {
      Vue.http.get('/api').then(response => {
        commit('setMovies', response.data);
      });
    }
  }
});
```

The `created` hook will now just dispatch an action:

_src/main.js_

```js
created() {
  this.$store.dispatch('getMovies');
}
```

## Results and benefits

Once Vue.js Cinema has been migrated to Vuex, what are the tangible benefits? There's probably not going to be any direct benefits to the user in terms of better performance etc, but it will make the life of the developers easier.

### Debugging

Now that the application data is being managed by Vuex, we can easily view any changes to it in Vue Devtools:

Vuex and Vue Devtools not only log a change, and the source of the change, but allow you to "rewind" the change so you can see exactly how it affects the application.

As creator [Evan You said](https://github.com/vuejs/vuex/issues/236#issuecomment-231754241): "The benefit of Vuex is that changes going through the store are trackable, replayable and restorable."

### Decoupling of components and state

In Vue.js Cinema, we track the checked filters in two arrays, one for time and one for genre. Adding and removing filters requires a function that was previously a method on the root instance. Using Vuex, we can abstract that logic into a mutation:

_src/store/index.js_

```js
mutations: {
    ...
    checkFilter(state, { category, title, checked }) {
      if (checked) {
        state[category].push(title);
      } else {
        let index = state[category].indexOf(title);
        if (index > -1) {
          state[category].splice(index, 1);
        }
      }
    }
  },
```

The advantage of this kind of decoupling is that it makes the code more logical and maintainable.

### Condensing templates

Without a store pattern like Vuex, we share data between components through the mechanisms of props and events, which need to be declared in a component's template. In a large application this can make templates quite verbose.

Managing shared data in Vuex allows this:

```html
<movie-list
  :genre="genre"
  :time="time"
  :movies="movies"
  :day="day"
></movie-list>
```

To go to:

```html
<movie-list></movie-list>
```

* * *

#### About Anthony Gore

I'm Anthony Gore and I'm a web developer with a crush on Vue.js. I'm a Vue Community Partner, curator of the weekly _Vue.js Developers Newsletter_, and the creator of _Vue.js Developers_.
