OpenReplay
Navigate back to the homepage
BLOG
Browse Repo
Back

Learn how Mapping Works In VueX

Samaila Bala
May 24th, 2021 · 3 min read

Managing state in Vue applications can be difficult especially when there are so many moving parts in your application. Vuex a state management library for Vue applications helps simplify that process but can also get cumbersome and bloat your codebase which brings us to mapping.

Mapping in Vuex helps you make use of multiple store properties (state, getters, actions, and mutations) in your Vue components. In this article we will be looking at how to use Mapping to map data from a Vuex store to Vue components.

This article assumes you have prior knowledge of Vue and Vuex. If not, I suggest you read this article I wrote to become more familiar with the primary concepts of Vuex.

Why Mapping?

As I already explained Vuex allows us to manage state in Vue applications and provides a central store to keep properties such as state, mutations, getters, and actions. Below is an example of a typical Vuex store

1import Vue from 'vue';
2import Vuex from 'vuex';
3Vue.use(Vuex);
4export const store = new Vuex.Store({
5 state: {
6 products: [],
7 },
8 mutations: {
9 setProduct() {},
10 },
11 getters: {
12 getProduct() {},
13 },
14 actions: {
15 FETCH_PRODUCTS() {}
16 },
17});

To access the items in state in our Vue components we make use of the computed property by doing this:

1computed: {
2 getProducts(){
3 return this.$store.state.products
4 }
5}

While this method for handling data seems efficient for most applications It has a drawback: when the application becomes larger (and because we have a centralized store) the code may become bloated when we introduce more data to our application. Check out the following example:

1import Vue from 'vue';
2import Vuex from 'vuex';
3Vue.use(Vuex);
4export const store = new Vuex.Store({
5 state: {
6 products: [],
7 cart: [],
8 notifications: []
9 product: null
10 },
11 mutations: {
12 setProduct() {},
13 setCart() {},
14 setNotificationStatus(id) {}
15 },
16 getters: {
17 getProduct() {}
18 getCartTotalPrice() {},
19 getCartItemTotal() {}
20 getNotifications() {}
21 },
22 actions: {
23 SET_PRODUCT() {},
24 SET_CART() {},
25 FETCH_PRODUCTS(){},
26 SET_NOTIFICATION_STATUS() {}
27 },
28});

If we need all this data in a component our computed property becomes bloated as well:

1computed: {
2 getProducts(){
3. return this.$store.state.products
4 }
5 getCart(){
6 return this.$store.state.cart
7 }
8 getProduct(){
9 return this.$store.state.product
10 }
11 getNotifications(){
12 return this.$store.state.notifications
13 }
14 getCartTotalPrice(){
15 return this.$store.getters.getCartTotalPrice
16 }
17 getCartItemTotal(){
18 return this.$store.getters.getCartItemTotal
19 }
20},
21
22methods: {
23 setProduct: function() {
24 this.$store.commit('setProduct');
25 },
26 setCart: function() {
27 this.$store.commit('setCart');
28 },
29 setNotificationStatus: function(notificaionId) {
30 this.$store.commit('setProduct', notificationId);
31 }
32 fetchProducts: function() {
33 this.$store.dispatch('FETCH_PRODUCTS');
34 }
35}

Mapping allows us to structure the code better by binding the store properties (state, getters, mutations, and actions) to computed properties so we can use these properties directly in the state and save time.

In the next sections, we will look at how to use mapping to write less verbose code.

Mapping State

The state is a representation of our application at any point in time and contains data like objects, arrays, strings, etc. Vuex uses a single state tree to keep all our application-level states.

The question then becomes: What happens when we have “too much state” in our Vue components. Vuex provides a helper function called mapState to solve this problem. It is used for mapping state properties in the store to computed properties in our components.

1import { mapState } from 'vuex'
2
3export default{
4 computed: {
5 ...mapState([
6 'products','product','cart','notifications'
7 ])
8 }
9}

The mapState helper function returns an object which contains the state in the store. This state can then be accessed in components by doing this {{products}}.

We can also provide aliases for the state returned by the mapState function by returning an object instead of an array like the example below

1import {mapState} from 'vuex'
2
3export default{
4 computed: {
5 ...mapState({
6 // using an arrow function
7 productList: (state) => state.products,
8 // passing the string value is the same as state => state.cart
9 cartList: 'cart'
10 })
11 }
12}

The snippet’s code is cleaner and more readable than creating individual methods like the example below to return state properties:

1computed: {
2 getProducts(){
3 return this.$store.state.products
4 }
5 getCart(){
6 return this.$store.state.cart
7 }
8 getProduct(){
9 return this.$store.state.product
10 }
11 getNotifications(){
12 return this.$store.state.notifications
13 }
14},

Notice that the mapState helper should only be used when you have lots of data in the state. This is to avoid memory and performance issues in the long run.

Mapping Getters

Mapping getters is similar to mapping state. Getters provide a way of getting a derived computed state from the store e.g a function that returns products based on popularity. Vuex also provides a mapGetters helper function to map getters to local computed properties. The example below shows how to use the mapGetters function:

1import {mapGetters} from 'vuex'
2
3export default{
4 computed: {
5 ...mapGetters([
6 'getProduct' ,
7 'getCartTotalPrice',
8 'getCartItemTotal',
9 'getNotifications'
10 ])
11 }
12}

The mapGetters function returns an object of getters from the store. You can also alias the getters by using an object instead of an array

1import {mapGetters} from 'vuex'
2
3export default{
4 computed: {
5 ...mapGetters({
6 singleProduct: 'getProduct' ,
7 cartTotalPrice: 'getCartTotalPrice',
8 cartTotalItems: 'getCartItemTotal',
9 notifications: 'getNotifications'
10 })
11 }
12}

Mapping Mutations

Mutations are what differentiate Vuex from other popular state management libraries as they help in changing state in the store by committing a mutation as opposed to using reducer functions. The example below shows how to commit a mutation

1methods: {
2 setProduct: function(todo) {
3 this.$store.commit('setProduct');
4 },
5 setCart: function(todo) {
6 this.$store.commit('setCart');
7 },
8 setNotificationStatus: function(notificationId) {
9 this.$store.commit('setProduct', notificationId);
10 }
11 }

Mutations can also be mapped using the mapMutations helper function but unlike states and getters mutations are mapped to methods and not computed properties. The example below shows how to map a mutation

1import { mapMutations } from 'vuex';
2export default {
3 methods: {
4 ...mapMutations([
5 'setProduct', // maps this.setProduct to this.$store.commit('setProduct')
6 'setCart', // maps this.setCart to this.$store.commit('setCart')
7 // this accepts a payload
8 'setNotificationStatus', // maps this.setCart to this.$store.commit('setNotificationStatus', notificationId),
9 ]),
10 },
11};

You can also alias the mutations by passing an object instead of an array

1import { mapMutations } from 'vuex';
2
3export default {
4 methods: {
5 ...mapMutations({
6 addProduct: 'setProduct',
7 addProductToCart: 'setCart',
8 markNotification: 'setNotificationStatus', // this accepts a payload,
9 }),
10 },
11};

Mapping Actions

Mapping actions are very similar to mutations as actions are also mapped to the methods property and not the computed property. The major difference between actions and mutations is actions commit mutations and are asynchronous. The example below shows how it is used

1import { mapActions } from 'vuex';
2
3export default {
4 methods: {
5 ...mapActions([
6 'SET_PRODUCT', // maps this.SET_PRODUCT() to this.$store.dispatch('SET_PRODUCT')
7 'SET_CART', // maps this.SET_CART() to this.$store.dispatch('SET_CART')
8 'FETCH_PRODUCTS', // maps this.FETCH_PRODUCTS() to this.$store.dispatch('FETCH_PRODUCTS'),
9 ]),
10 },
11};

You can also alias the actions by passing an object instead of an array to the mapActions function

1import { mapActions } from 'vuex';
2export default {
3 methods: {
4 ...mapActions({
5 setProduct: 'SET_PRODUCT',
6 setCart: 'SET_CART',
7 fetchProducts: 'FETCH_PRODUCTS',
8 }),
9 },
10};

Mapped mutations and actions can be used in templates the same way other mutations and actions are used. The example below shows how to use an action in a template

1<button v-on:click="setCart">Add to Cart</button>

Conclusion

In this article, we looked at the concept of mapping in Vuex and how it can help you structure your code better. Something to note is that Mapping is beneficial when a component needs to use multiple store properties and should only be used for that.

Measuring front-end performance

Monitoring the performance of a web application in production may be challenging and time-consuming. OpenReplay is an open-source alternative to FullStory and LogRocket. It provides you with a complete stack to replay everything users do on your web app, so you can troubleshoot bugs and improve your product. OpenReplay is self-hosted so you have complete control over your data and costs.

OpenReplay lets you reproduce issues, aggregate JS errors and monitor your app’s performance. We offer plugins for capturing the state of your Redux or VueX store and for inspecting Fetch requests and GraphQL queries.

OpenReplay

Happy debugging, for modern frontend teams - Start monitoring your web app for free.

More articles from OpenReplay Blog

Should Developers Only Use the CLI?

Some people believe true developers only use the CLI, what do you think?

May 24th, 2021 · 7 min read

Step-by-step Guide To Building and Deploying a Vue JS App with Netlify in 2021

Building and deploying your own apps with VueJs has never been so easy, learn how to deploy your Vue apps with Netlify in this detailed tutorial

May 17th, 2021 · 4 min read
© 2021 OpenReplay Blog
Link to $https://twitter.com/OpenReplayHQLink to $https://github.com/openreplay/openreplayLink to $https://www.linkedin.com/company/18257552