Hello! We would like to bring to your attention the
article by Anthony Gore on the migration of Vue.js applications to Vuex.
Type of application to be migratedThe following is a translation of the article. All who are interested in this topic, I invite under the cat.
One of the difficulties in mastering Vuex is that it is not so much a library as a design pattern. It follows from this that working with Vuex is not so much working with an API, as it is structuring your code according to a pattern. If you're new to Vuex, it can be daunting.
')
In this article, I will demonstrate how to start migrating an existing Vue.js application to Vuex. I'll show you how to identify those parts of your application that should belong to Vuex, and those that should not be transferred, how to turn the functions of your component into mutations, actions, and so on, and finally, we will discuss what benefits we will get as a result .
If you are not sure whether you should use Vuex, I recommend that you first read this article here: β What is Vuex: A Beginner's Guide to Vue Data Storage β
Case Study: Vue.js Cinema
As an educational example, we will take the demo application Vue.js-cinema on Vuex. This application, consisting of a single file, built on the components of Vue, is quite a good candidate for demonstrating the migration to Vuex, as it contains a significant amount of states.

If you want to know how to build a Vue.js cinema from scratch, this is part of my full development course on Vue.js.
Remember that the goal of Vuex is to manage the state of the application. From this it follows that in order to migrate a Vue.js application to Vuex, we must determine what its state will be. We will soon see the state in the code, but it is useful to first understand what it will be, by simply studying what the application generally does, for example, in our case, it displays a list of movies that can be filtered by day, session time or genre.
What application data should belong to Vuex?
Using Vue Devtools, or just a code inspector, we can see the data belonging to each vue component:

Our task is not to transfer all data to the Vuex Store (central data repository). Instead, we want to define data that:
- Changes over the life cycle of the application (static data does not require special management).
- Divided between several objects / components.
This is what we are talking about when we pronounce the state of the application, and this is exactly what we want to put in the repository.
For example, take a look at this group of
check-filter
components, custom checkboxes for filtering movies:

Each
check-filter
component has a
checked
property, as well as text that is passed to it as a property, in particular,
Before 6pm ,
After 6pm, and so on:
src / components / CheckFilter.vue <template>...</template> <script> export default { data() { return { checked: false } }, props: [ 'title' ], ... } </script>
The
checked
property is responsible for the state of each checkbox in an application, and therefore it belongs to the state of the application as a whole, since it can change throughout the application's life cycle, and other components must respond accordingly to changes in the state of these checkboxes.
The
title
property, on the other hand, does not change and does not affect other components in any way. Therefore, we do not need to control them with the Vuex-Store.
Note: if you have any local state that you would like to monitor with Vue DevTools, then itβs ok if you add it to the store; This is not a violation of the pattern.
Properties β Vault (Stor)
If you designed your application using a component, as I did with the Vue.js cinema, then the first place to look for the data that you would like to put into the store would be the component properties. Especially those properties through which the same data is transmitted to different components.
For example, I pass the
day
property from the root component of the application to the
day-select
and
movie-list
components. Using the day-select component, the user selects the day for which he wants to watch movies, and the movie list is filtered according to the selected value:
Day-select componentTo move the
day
to Vuex, we can simply remove it from the root component and move it to the state object of the Vuex repository:
export default new Vuex.store({ state: { day: moment()
Now we can remove the binding from the template
v-bind:day="day"
, and in the component replace the standard property with a computed property that refers to our repository (store). In the case of the
day-select
component, this will be the following code:
export default { props: [ 'day' ], ... }
which is converted to
export default { computed: { day() { return this.$store.state.day } } }
Events β Mutations
While properties are data that is passed to a component, events affect the state of that data. Event listeners in your code must be converted to Vuex mutations. Functions that trigger events will be redone, and will cause mutations, not events.
Let's return to our example with the
day-select
component. When the user changes the day by clicking on the corresponding interface element, the following component method is called:
selectDay(day) { this.$emit('setDay', day); }
The root component contains an event listener that will respond to a custom event:
created() { this.$on('setDay', day => { this.day = day; }); }
Now the listener function can be transferred from the root component to the mutation object of our repository with minor changes:
src / store / index.js export default new Vuex.Store({ state: { day: moment() }, mutations: { setDay(state, day) { state.day = day; } }
Next, we need to replace the event call in the component with the mutation call of our repository:
selectDay(day) { this.$store.commit('setDay', day); }
Finally, we can also remove the event listener from the template, i.e. code
v-on:click="setDay"
.
AJAX β Actions
Vuex actions are a mechanism for handling asynchronous mutations. If you use AJAX to update the state of your application, you may need to wrap it in an action.
In the Vue.js cinema, I use AJAX (using the Vue Resource HTTP client) to get data from my server's API:
src / main.js created() { this.$http.get('/api').then(response => { this.movies = response.data; }); }
This happens only once during the application's life cycle, when it is only created, so this action seems too trivial to use Vuex in this case, but there is no harm in this, and we will get an advantage in debugging our application with Vuex.
Actions are invoked from the application and must in turn trigger a mutation in the central repository when the asynchronous action is complete. Here is the code that implements it:
src / store / index.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
method should now only invoke the action:
src / main.js created() { this.$store.dispatch('getMovies'); }
Results and Benefits
Now that we have migrated the Vue.js cinema to Vuex, what benefits did we get? Perhaps for the end user there will not be any improvement in page loading speed, performance, and so on, but this will greatly simplify the life of the developers.
Debugging
Now that our application is managed through Vuex, we can easily see any changes in it using Vue Devtools:

Vuex and Vue Devtools not only log changes to the repository, but also allow you to rewind the changes, so you can step by step track how they affect the application.
As the library's creator,
Evan View, said : βThe advantage of Vuex is that changes in it are traceable, reproducible, and recoverable.β
Separation of components and state
In the Vue.js cinema, we track the filters in two arrays, one of which contains data about the time of the session, the other - the film genre. Adding and removing filters was previously processed by a function in the root component. Using Vuex, we can transfer this logic to a mutation in our repository:
src / store / index.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 separation is that the code thus becomes more readable, logical and supported.
Reduction component
Without a storage pattern like Vuex, we pass the data to the components in the form of properties and events that need to be declared in the HTML template. In large applications, because of this, patterns can become quite verbose.
Data management in Vuex allows this code:
<movie-list :genre="genre" :time="time" :movies="movies" :day="day" ></movie-list>
convert to this:
<movie-list></movie-list>
Like this article?
Subscribe to the newsletter and get the latest articles on Vue.js in the mail.