Managing State with Vuex - the Guide I Wish I'd Had
Lauri Hiltunen
Posted on March 28, 2018
TL;DR: see the vuex flow and/or skip to see the code.
Frontend apps have been growing more and more feature-rich in recent years. "It's for the web" is not a proper reason to deny desktop-like feature requests anymore. At the same time frontends are switching from the traditional MVC model to a more componentized structure, and the need for a solid state management pattern has emerged. After all, the components interacting with each other is a vital part of any bigger app.
Flux is a design pattern released by Facebook, created to structure client-side, component-based applications. There are many implementations of the Flux-pattern but in this post we're going to focus on one: Vuex. This is the guide I wish I'd had when I first started reading about state management with Vuex. There will be code!
Concepts
The key concepts with Vuex are: the state, actions, mutations and getters. The state object contains the application state, and is shared with all the components. Mutations change the state - and they are the only way to change it. Actions commit mutations, the key difference being that mutations can not be asynchronous. We should invoke async actions which commit mutations when the async code has completed. All state mutations must be synchronous! Finally the getters return specific parts of the state for components to use.
You can choose not to use some of the steps described above, but for the sake of completeness I'll go through the flow as it's designed to be used.
The sample app
We're going to take a look at some code, which creates the store for one property, mutates it and returns it for components. The sample app is a concept of an activity calculator of some sorts. The basic idea is that you'll select an exercise you're working with and then add the amount of that exercise done, like stairs climbed, the distance you've ran or the pushups you've done. The app for this example consists of two components: one that selects the exercise and the other one that uses the selected exercise and allows you to mark the "reps" you've accomplished and send the data to a backend service for further processing.
Bring on the code
Let's get going with the code - I did use the vue-cli simple webpack setup to enable ES6 features. First of all, let's create the Vuex store.
The state inside store.js
The state inside the store is just another object, it can contain anything you want.
Actions
Then we're having the action methods, they get the context as their first parameter and the possible payload as the second param. This action creates a mutation by calling context.commit with the name of the mutation and passing possible payload to go with it.
Mutations
And then there are the mutations. Mutations get the state as first parameter and an optional payload as second. The action from previous step committed a mutation which calls the selectExercise method which in turn changes the state for real.
Getters
The last missing part - the getters exposed by the store. You can call the selectedExercise getter from any of your components and it'll return you that specific portion of the state.
Exporting the Vuex store
Build up the store and export it so we can use it.
//store.js
export default new Vuex.Store({
state,
actions,
mutations,
getters
})
Import the store and use it in your app
Initialising the app with the store.
Using the store inside components
Running actions and mutating the state
Now that we've set up the store, we can use it in our components. First of all the exercise-selector component, which triggers the action that selects the active exercise for our context by running the select exercise action which in turn runs the mutation that commits the change to state.
Getters
After taking care of mutating the state, we're mapping the getters defined in the store to our other component. This effectively creates a computed getter method with the name "selectedExercise" for our component.
When the getter is in our component's context, we can use it in our template as follows.
So we are using the mapped getter method inside our template. This effectively gets the data from store and is updated automatically when any component commits the mutation that changes the selected exercise.
And that's it, Vuex with a couple of lines of code.
Afterword
I got into Vuex a couple of weeks ago during a get-together with my colleagues. At first all the talk about actions and mutations seemed a bit confusing and complicated, but to see it in a few lines of code makes it quite clear and understandable. And in the end using centralized state does make application development easier as the size of the application gets bigger. When the state changes are reactively rendered in every component, you can focus on the key features which alter the state instead of doing something like emitting events or updating your views manually.
I like it, it beats all the manual scripting and event-based solutions I've seen before. By a mile!
Posted on March 28, 2018
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.