The basics of mapState in Vuex

To get started with mapState function in Vuex, you need to install vue and vuex first.

In this articles, I will be using vuex 3, this may apply to other versions as well.

This is an example from Vuex official tutorial:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment (state) {
state.count++
}
}
})

new Vue({
el: '#app',
store, // ES6 syntax, short for `store: store`
})

In your custom Counter component, it may look like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<script>
export default {
computed: {
count() {
return this.$store.state.count; // Use it as a computed property
}
},
methods: {
handleClick: function(e) {
console.log('count:', this.$store.state.count)
this.$store.commit('increment'); // commit a mutation to increase the count
console.log('after commit count:', this.$store.state.count)
}
}
}
</script>

<template>
<h1 @click="handleClick">{{ count }}</h1>
</template>

If there are many computed properties which make use of state properties from the store, it will soon become very repetitive. To make a better developer experience, Vuex introduced the mapState helper function.

1
2
3
4
5
6
7
8
import { mapState } from 'vuex'
export default {
// ...
computed: mapState([
// map this.count to store.state.count
'count'
])
}

In the previous example, we use the return value of mapState as the value of computed property. But what happens when we have other computed properties? In this case, we need to copy its return value to the computed property list. For example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<script>
import { mapState } from 'vuex';
export default {
data() {
return {
firstName: 'Kang',
lastName: 'CHEN'
}
},
computed: {
fullName: function() { // another computed property
return this.firstName + ' ' + this.lastName;
},
...mapState(['count']) // ES6 syntax, copy the return Object with the spread operator
},
methods: {
handleClick: function(e) {
console.log('count:', this.$store.state.count)
this.$store.commit('increment');
console.log('after commit count:', this.$store.state.count)
}
}
}
</script>

<template>
<div>
<h1 @click="handleClick">{{ count }}</h1>
<p>{{ fullName }}</p>
</div>
</template>

When you project grows bigger and more complicated, there are more states in your single state tree, making it more difficult to maintain. It is a great idea to divide our store into modules. For example, you can create a file named store/user.js to save all the state related to user:

1
2
3
4
5
6
7
export default {
namespaced: true,
state: {
firstName: 'Kang',
lastName: 'CHEN'
}
}

Then import it in your main.ts:

1
2
3
4
5
6
7
8
9
10
import user from './store/user'

// ...

const store = new Vuex.Store({
// ...
modules: {
user
}
})

In our component:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<script>
import { mapState } from 'vuex';
export default {
computed: {
fullName: function() {
return this.firstName + ' ' + this.lastName;
},
...mapState('user', ['firstName', 'lastName'])
},

}
</script>

<template>
<div>
<p>{{ fullName }}</p>
</div>
</template>

['firstName', 'lastName'] is an array of state property names from the user module that you want to map to computed properties in your component, they will be available in your component’s template as computed properties, we can also use them in other computed properties such as fullName.