VueJs: Introduction to Vuex
When you are working with Vue, passing the state up and down in your components is quite normal and, if you are working on a small application, probably this is not going to give you any problems.
But as soon as your application start having a lot of components that sometimes are nested 2 or 3 levels down, maintaining the state starts to feel complicated and messy. If you feel like you are in this situation you should start considering using Vuex, not sooner or later.
You need to understand, like in most cases, when you choose to use a tool you are having a trade-off and this is not different when it comes to the decision of using Vuex. In the VueJs team words:
Although Vuex helps us deal with shared state management, it also comes with the cost of more concepts and boilerplate. It’s a trade-off between short term and long term productivity.
In this article we are going to do a small introduction to Vuex and then we are going to go through some examples.
Vuex is a pattern based on flux, redux and Elm architecture. One of the good things of Vuex is that is maintained by the Vue team so they work perfect together.
The objective of Vuex is to provide a predictable state management with a centralized store for all the components in your application. It enforces the usage of some rules in order to manage the state which also helps to provide a better structure and maintainability to our code.
Vuex key concepts
Let’s go through some of the key concepts that you have to understand when you are using Vuex (we are also going to see most of them latter in code examples).
Your components can use the global store state of your application and also have their own state. Any information that you are going to need in multiple components should be in the store state.
In order to have access to the store on all your components, you need to add it to your root component.
You have to initialize the properties of the state of your application when you declare your store.
Change the store state
There are two ways to change the store state from your components.
- Commit Mutations
Mutations are operations to our state managed by our store. You can’t execute them directly from your components, in order to execute a mutation you have to use the store “commit” method, that receives the name of the mutation to execute and may receive and an object containing custom data.
Mutations are synchronous.
- Dispatch Actions
Your store may also contain actions. In order to execute an action from your components you have to execute the method “dispatch” of the store, this method also receives the name of the action to dispatch and an object containing custom data. Actions end up committing mutations, they don’t change the sate directly.
Actions can be asynchronous and can return promises.
The main reason for the existence of actions and mutations is for separations of concerns between synchronous and asynchronous operations.
When the store state changes any component using that part of the state is going to react and update.
They are like computed properties for your store. Getter’s result is cached based on its store state dependencies, and will only re-evaluate when some of its dependencies have changed.
As your application grows a single declaration of your store can get really messy. In order to deal with this, you can divide your store in modules, each of them can contain all the store features. Finally, you can add all these modules to your store declaration.
Let’s go now to see some examples!…
Is party time!…
Initialization of a Store
We are going to create a store with some of the store features that we mentioned before.
Wow! … Don’t worry we are going to dig into that implementation.
The first thing we need to do is to instantiate our store using Vuex Store.
Here we declare and initialize the properties of the state of our store.
This is our computed getter to obtain the reversed version of userName state property. These functions receive the state as the first parameter.
These are the two mutations that we are going to provide in order to change our state. They also receive the state as the first parameter.
We are going to provide only one async action that returns a promise. Actions receive a context that is a representation of the state. Actions always end up calling a mutation with the store “commit” function to change the state. In this case, the promise is resolved and returns the new value of the count property.
Add the store to our root component
This is simple. We just need to set the property store in out root component. Now all the components of our application have access to the store.
Components using the store
We are going go through some examples of components using Vuex and explaining what they are doing.
This component has two computed properties. They are set by using the mapState helper of Vuex, the objective of this helper is to simplify mapping the store state to our component when we are using multiple store state properties or getters. Is not really necessary in this example but is worth showing it.
- First, we are creating a userFullName computed property that receives the state and returns the concatenation of two state properties (this should be done with a computed getter in the store, but we are doing it this way as an example).
- Then we are using the spread (…) array to add to the component computed properties one of the getters declared in our store. We are also using a Vuex helper, in this case, the mapGetters.
Both of the helpers (mapState and mapGetters) can be used providing an array of strings (we use this approach when the component property has the same name as the store state property, or getter) or they can also be used passing an object (key value representation of components properties). More info about mapState: https://vuex.vuejs.org/en/state.html
In this second example, we can see how to use a v-model with store data and how to execute an store action.
- First, declare a computed property called “userName” that gets the “userName” value of the store state and when it changes, the computed executes a setter that uses the store “commit” to trigger the “changeName” mutation and also provides the new value as a payload param.
- We also add a method using the helper “mapActions”, this helper works in the same way that the ones we saw before. The spread (…) operator is not really needed in this case because there are no other methods but, since in a real life application you are going to have other methods, is good to get used to seeing it. Inside the helper, we declare an add method that dispatches the action “increment” of the store. Since this action returns a promise we can use a “then” with a callback.
The $store is accessible in this component because we add it in the root component of our application.
Vuex is powerful and simple to use but using it’s not a trivial decision, as we discuss in this article, is a trade off so be sure you are getting more than you are losing!