Composing Actions #
Editor’s note: This post was updated on 29 November 2021 to reflect upgrades to Vuex. Vuex is a double-edged sword. If used properly, it can make your life a lot easier when working with Vue. It can also make a mess of your codebase if you’re not careful.
There are four main concepts you should understand before you use Vuex: state, getters, mutations, and actions. A simple Vuex state manipulates data within these concepts in the store. Mapping in Vuex provides a nice, clean way of retrieving data from them.
In this tutorial, we’ll demonstrate how to map data from the Vuex store. If you’re a Vue developer who’s familiar with the basics of Vuex, these best practices will help you write cleaner and more maintainable code.
Let’s get started! Mapping in Vuex enables you to bind any of the state’s properties, like getters, mutations, actions, or state, to a computed property in a component and use data directly from the state.
Below is an example of a simple Vuex store with test data in the state:. If you want to access the value of data from the state, add the following in your Vue.js component:.
The above code works but quickly gets ugly as data in the state starts to grow. To get the username from the user object in the state:. Although we can get the job done with this.$store.state.user.data.name, we can use a map helper to simplify it to this.event.
To map the state in our component, we first import mapState and add a computed property to our component:.
The three-dot syntax used above is an ES6 syntax known as the spreadsyntax. You now have access to the entire user object within the component, therefore, user becomes a computed component.
You can do more, like adding objects from the state to the mapState method:.
As you can see, this code is a lot cleaner. You can easily access the username with the following:. The same goes for the services object and many other values mapped.
Did you notice how we passed in an array to the mapState()? If you need to give the value a different name, you can pass in an object instead as follows:. Now, you can reference the user by simply calling userDetails. At first, you shouldn’t map the Vuex state.
As a rule of thumb, you should map the Vuex state only when you have a lot of data in the state and need it in the component. In the example above, it wouldn’t make much sense to map the entire user object if we only need one value from it, for example, the username.
When you map the state, the entire object is loaded into memory. You should avoid loading unnecessary data to memory because it would lead to negative performance implications in the long run.
Getters provide a way to get a derived computed state from the store. Mapping getters is similar in syntax to the mapState function:.
The code above is similar to writing the computer properties as follows:. Like the mapped state, you can pass in an object to the mapGetters function if you intend to use a different name:.
Mutation is a way to change state in the Vuex store. Unlike mapState and mapGetters, which are mapped in the computed property of Vue to make data on the state reactive with data in the component, Mutations are mapped in the method. When you map your mutations, you can commit your mutation using the following syntax in Vue:.
Mapping actions is a lot like mapping mutations because it is also performed in the method. Actions are also mapped to the methods property and not the computed property.
Using a mapper binds this.$store.dispatch('actionName') to the name in the array of the mapper or the key of the object:. Note how we used an array to define multiple map actions, which is similar to writing the computer properties as follows:.
Now, you should have a firm understanding of how mapping in Vuex works and why you should use it. You should be able to map all the components in the Vuex store, like state, getters, mutations, and actions. Additionally, you’ve learned when to map the store and when you shouldn’t.
Another advantage of mapping your actions, getters, and mutations is that it will make your code smaller and save you some time writing.
These best practices will help you immensely if you decide to use Vuex in your next project. I hope you enjoyed this tutorial. Actions are similar to mutations, the differences being that:. Instead of mutating the state, actions commit mutations. Actions can contain arbitrary asynchronous operations.
Let's register a simple action:. Action handlers receive a context object which exposes the same set of methods/properties on the store instance, so you can call context.commit to commit a mutation, or access the state and getters via context.state and context.getters.
We can even call other actions with context.dispatch. We will see why this context object is not the store instance itself when we introduce Modules later.
In practice, we often use ES2015 argument destructuring to simplify the code a bit (especially when we need to call commit multiple times):. Actions are triggered with the store.dispatch method:. This may look silly at first sight: if we want to increment the count, why don't we just call store.commit('increment') directly?
Remember that mutations have to be synchronous. We can perform asynchronous operations inside an action:. Actions support the same payload format and object-style dispatch:. A more practical example of real-world actions would be an action to checkout a shopping cart, which involves calling an async API and committing multiple mutations:.
Note we are performing a flow of asynchronous operations, and recording the side effects (state mutations) of the action by committing them. You can dispatch actions in components with this.$store.dispatch('xxx'), or use the mapActions helper which maps component methods to store.dispatch calls (requires root store injection):.
Actions are often asynchronous, so how do we know when an action is done?