DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones AWS Cloud
by AWS Developer Relations
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones
AWS Cloud
by AWS Developer Relations
Securing Your Software Supply Chain with JFrog and Azure
Register Today

Trending

  • DZone's Article Submission Guidelines
  • Is Podman a Drop-In Replacement for Docker?
  • Effective Java Collection Framework: Best Practices and Tips
  • Microservices With Apache Camel and Quarkus

Trending

  • DZone's Article Submission Guidelines
  • Is Podman a Drop-In Replacement for Docker?
  • Effective Java Collection Framework: Best Practices and Tips
  • Microservices With Apache Camel and Quarkus
  1. DZone
  2. Coding
  3. JavaScript
  4. Migrating a Vue.js App to Vuex

Migrating a Vue.js App to Vuex

Curious about Vue's application data store? Read on to learn how to move your exiting Vue.js project to Vuex, and get an expert's opinion on what this does.

Anthony Gore user avatar by
Anthony Gore
CORE ·
Updated Feb. 04, 20 · Tutorial
Like (5)
Save
Tweet
Share
9.75K Views

Join the DZone community and get the full member experience.

Join For Free

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.

Case Study: Vue.js Cinema

As a case study, we'll migrate a demonstration app I made called Vue.js Cinema 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.

Example application

Example application


Remember that Vuex's purpose is to manage an application's 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.

You may also like: Vue Tutorial 5 — Form Data Binding.

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:

State in Vuex

State in Vuex


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:

Filtering results

Filtering results


Each check-filter component has a checked data property, and also a title that is passed to it as a prop, e.g. Before 6 pm, After 6 pm, etc.:

src/components/CheckFilter.vue

HTML
 




x
12


 
1
<template>...</template>
2
<script>
3
  export default {
4
    data() {
5
      return {
6
        checked: false
7
      }
8
    },
9
    props: [ 'title' ],
10
    ...
11
  }
12
</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-filter 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.

Image title

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:

JavaScript
 




xxxxxxxxxx
1


 
1
export default new Vuex.store({
2
  state: {
3
    day: moment() // the initial value
4
  },
5
  ...
6
});



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:

JavaScript
 




xxxxxxxxxx
1


 
1
export default {
2
  props: [ 'day' ],
3
  ...
4
}



Goes to:

JavaScript
 




xxxxxxxxxx
1


 
1
export default {
2
  computed: {
3
    day() {
4
      return this.$store.state.day
5
    }
6
  }
7
}



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:

JavaScript
 




xxxxxxxxxx
1


 
1
selectDay(day) {
2
  this.$emit('setDay', day);
3
}



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

JavaScript
 




xxxxxxxxxx
1


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



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

JavaScript
 




xxxxxxxxxx
1


 
1
export default new Vuex.Store({
2
  state: {
3
    day: moment()
4
  },
5
  mutations: {
6
    setDay(state, day) {
7
      state.day = day;
8
    }
9
  }



A mutation commit will now replace the event emit in the day-select component:

JavaScript
 




xxxxxxxxxx
1


 
1
selectDay(day) {
2
  this.$store.commit('setDay', day);
3
}



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

JavaScript
 




xxxxxxxxxx
1


 
1
created() {
2
  this.$http.get('/api').then(response => {
3
    this.movies = response.data;
4
  }); 
5
}



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 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

JavaScript
 




xxxxxxxxxx
1
19


 
1
export default new Vuex.Store({
2
  state: {
3
    ...
4
    movies: []
5
  },
6
  mutations: {
7
    ...
8
    setMovies(state, movies) {
9
      state.movies = movies;
10
    }
11
  },
12
  actions: {
13
    getMovies({ commit }) {
14
      Vue.http.get('/api').then(response => {
15
        commit('setMovies', response.data);
16
      });
17
    }
18
  }
19
});



The created hook will now just dispatch an action:

src/main.js

JavaScript
 




xxxxxxxxxx
1


 
1
created() {
2
  this.$store.dispatch('getMovies');
3
}



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:

Debugging application

Debugging application


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: "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

JavaScript
 




xxxxxxxxxx
1
13


 
1
mutations: {
2
    ...
3
    checkFilter(state, { category, title, checked }) {
4
      if (checked) {
5
        state[category].push(title);
6
      } else {
7
        let index = state[category].indexOf(title);
8
        if (index > -1) {
9
          state[category].splice(index, 1);
10
        }
11
      }
12
    }
13
  },



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:

JavaScript
 




xxxxxxxxxx
1


 
1
<movie-list
2
  :genre="genre" 
3
  :time="time" 
4
  :movies="movies" 
5
  :day="day"
6
></movie-list>



To go to:

JavaScript
 


xxxxxxxxxx
1
 
1
<movie-list></movie-list>



Further Reading

  • Components and How They Interact in Vue and Vuex.
  • Vue Example: Creating a TODO App using Vue.js 2, Vuex, and Codemix [Video].
  • How and Why We Moved to Vue.js.
Vue.js app application Data (computing) JavaScript Event

Published at DZone with permission of Anthony Gore, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Trending

  • DZone's Article Submission Guidelines
  • Is Podman a Drop-In Replacement for Docker?
  • Effective Java Collection Framework: Best Practices and Tips
  • Microservices With Apache Camel and Quarkus

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com

Let's be friends: