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!
mapState
mapGetters
?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:
import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) const store = new Vuex.Store({ state: { data: "test data" } } })
If you want to access the value of data
from the state, add the following in your Vue.js component:
computed: { getData(){ return this.$store.state.data } }
The above code works but quickly gets ugly as data in the state starts to grow. For example:
import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) const store = new Vuex.Store({ state: { user: { id:1, age:23, role:user data:{ name:"user name", address:"user address" } }, services: {}, medical_requests: {}, appointments: {}, } } })
To get the username from the user object in the state:
computed: { getUserName(){ return this.$store.state.user.data.name } }
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
.
mapState
To map the state in our component, we first import mapState
and add a computed property to our component:
import { mapState } from 'vuex'; export default{ computed: { ...mapState([ 'user', ]) } }
The three-dot syntax used above is an ES6 syntax known as the spread syntax. 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:
import { mapState } from 'vuex'; export default{ computed: { ...mapState([ 'user', 'services' ]) } }
As you can see, this code is a lot cleaner. You can easily access the username with the following:
{{user.data.name}}
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:
import { mapGetters } from 'vuex'; export default{ computed: { ...mapState({ userDetails:'user', userServices:'services' }) } }
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.
mapGetters
?Getters provide a way to get a derived computed state from the store. Mapping getters is similar in syntax to the mapState
function:
import { mapGetters } from 'vuex' export default { computed: { ...mapGetters({ first: ‘firstCount’, another: ‘anotherGetter’, }) } }
The code above is similar to writing the computer properties as follows:
export default { computed: { firstCount() { return this.$store.getters.firstCount }, anotherGetter() { return this.$store.getters.anotherGetter }, } }
Like the mapped state, you can pass in an object to the mapGetters
function if you intend to use a different name:
import { mapGetters } from 'vuex' export default { computed: { ...mapGetters({ first: ‘firstCount’, another: ‘anotherGetter’, }) } }
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:
this.$store.commit('mutationName`)
For example:
import { mapMutations } from 'vuex' export default { methods: { ...mapMutations([ 'search', // map `this.search()` to `this.$store.commit('search')` // `mapMutations` also supports payloads: 'searchBy' // map `this.searchBy(key)` to `this.$store.commit('searchBy', key)` ]), } }
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:
import { mapActions } from 'vuex' export default { methods: { ...mapActions([ 'search', // `mapActions` also supports payloads: searchBy(key) 'searchBy' ]), } }
Note how we used an array to define multiple map actions, which is similar to writing the computer properties as follows:
export default { methods: { search() { return this.$store.dispatch('search'); }, searchBy(key) { return this.$store.dispatch('searchBy', key); }, } }
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.
Debugging Vue.js applications can be difficult, especially when there are dozens, if not hundreds of mutations during a user session. If you’re interested in monitoring and tracking Vue mutations for all of your users in production, try LogRocket.
LogRocket is like a DVR for web and mobile apps, recording literally everything that happens in your Vue apps, including network requests, JavaScript errors, performance problems, and much more. Instead of guessing why problems happen, you can aggregate and report on what state your application was in when an issue occurred.
The LogRocket Vuex plugin logs Vuex mutations to the LogRocket console, giving you context around what led to an error and what state the application was in when an issue occurred.
Modernize how you debug your Vue apps — start monitoring for free.
Would you be interested in joining LogRocket's developer community?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowLearn how to implement one-way and two-way data binding in Vue.js, using v-model and advanced techniques like defineModel for better apps.
Compare Prisma and Drizzle ORMs to learn their differences, strengths, and weaknesses for data access and migrations.
It’s easy for devs to default to JavaScript to fix every problem. Let’s use the RoLP to find simpler alternatives with HTML and CSS.
Learn how to manage memory leaks in Rust, avoid unsafe behavior, and use tools like weak references to ensure efficient programs.
6 Replies to "Best practices for Vuex mapping "
Good guide :)) Thank you so much, this is just the beginning of learning VUE of the rest, but this entry is useful.
I liked your explanation, thank. I observed one probable mistake, you wrote “import mapGetters ” into the explanation about mapState. That’s right?
your mutation mapping example is messed up man. names are mis matched.
thanks but usage of modules & nameSpaces is missing 😉
Really well structured explanation.
Pleas fix only one small thing which I’ve noticed in ‘mapGetters’ section :
…mapGetters({
first: ‘firstCount’,
another: ‘anotherGetter’,
})
Thanks for bringing that to our attention. It should be fixed now!