方便的组件api

为了避免每次都需要通过this.$store来调用api,vuex提供了mapState、mapMutations、mapGetters mapActions、createNamespacedHelpers 等api,
可以很方便的在vue组件中进行使用,下面看看具体的使用方式。

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
32
33
34
35
36
37
38
39
<template>
<div class="cart">
<h2>Your Cart</h2>
<p v-show="!products.length"><i>Please add some products to cart.</i></p>
<ul>
<li
v-for="product in products"
:key="product.id">
{{ product.title }} - {{ product.price | currency }} x {{ product.quantity }}
</li>
</ul>
<p>Total: {{ total | currency }}</p>
<p><button :disabled="!products.length" @click="checkout(products)">Checkout</button></p>
<p v-show="checkoutStatus">Checkout {{ checkoutStatus }}.</p>
</div>
</template>

<script>
import { mapGetters, mapState } from 'vuex'

export default {
computed: {
//这里使用mapState
...mapState({
checkoutStatus: state => state.cart.checkoutStatus
}),
//这里使用了mapGetters
...mapGetters('cart', {
products: 'cartProducts',
total: 'cartTotalPrice'
})
},
methods: {
checkout (products) {
this.$store.dispatch('cart/checkout', products)
}
}
}
</script>

以上是vuex官方示例shopping-cart中一个组件(examples/shopping-cart/components/ShoppingCart.vue)。同样的,我们还能这样使用mapActions和mapMutations。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<script>
import { mapActions mapMutations } from 'vuex'

export default {
//...
methods: {
//这里使用了mapActions
...mapActions('cart', [
'addProductToCart'
]),
//这里使用了mapMutations
...mapMutations({
decrement: 'decrementProductInventory'
})
}
//...
}
</script>
  • 注:`…用的是es6中的对象展开式写法。

组件api实现解析

这几个组件api放在helpers.js文件中,我们先来看看mapState函数的源码。

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
//normalizeNamespace是进行参数处理,如果存在namespace便加上命名空间
export const mapState = normalizeNamespace((namespace, states) => {
const res = {}
//normalizeMap是对传入的states进行处理,也就是数据格式的统一
normalizeMap(states).forEach(({ key, val }) => {
//遍历,对参数里的所有state都包裹一层函数,最后返回一个对象
res[key] = function mappedState () {
let state = this.$store.state
let getters = this.$store.getters
if (namespace) {
//如果存在namespace,取该namespace下module的state和getters
const module = getModuleByNamespace(this.$store, 'mapState', namespace)
if (!module) {
return
}
state = module.context.state
getters = module.context.getters
}
//val是函数,把state和getters传递进去
return typeof val === 'function'
? val.call(this, state, getters)
: state[val]
}
// mark vuex getter for devtools
res[key].vuex = true
})
return res
})

这里我们回顾一下上面mapState的用法:

1
2
3
4
5
6
7
8
9
10
import { mapState } from 'vuex'
export default {
computed: {
//这里使用mapState
...mapState({
checkoutStatus: state => state.cart.checkoutStatus
})
}
/** 省略 **/
}

经过 mapState 函数处理后的结果:

1
2
3
4
5
6
7
8
9
import { mapState } from 'vuex'
export default {
computed: {
checkoutStatus() {
return this.$store.state.cart.checkoutStatus
}
}
/** 省略 **/
}

对比上面的mapState的用例和经过mapState函数处理后的结果,就可以很清楚的知道mapState函数就是在每个state包装一下,使原本需要在this.$store上取state的写法
变成 state => stat.cart 的写法而已。

同样的我们再来对比下mapGetters的写法和处理结果

1
2
3
4
5
6
7
8
9
10
11
12
13
//使用mapGetters的写法
import { mapGetters } from 'vuex'

export default {
computed: {
//这里使用了mapGetters
...mapGetters('cart', {
products: 'cartProducts',
total: 'cartTotalPrice'
})
},
/** 省略 **/
}
1
2
3
4
5
6
7
8
9
10
11
12
//mapGetters处理后的结果
export default {
computed: {
products() {
return this.$store.getters['cart']['cartProducts']
},
total() {
return this.$store.getters['cart']['cartTotalPrice']
}
}
/** 省略 **/
}

好,现在是彻底明白了,mapState、mapGetters函数其实就相当于一种语法糖,将原本需要this.$store来获取数据的写法变成另外一种更加简易的写法。

mapActions、mapMutations的功能大同小异,这里就不再赘写了。

小结

本节主要就讲mapState、mapMutations、mapGetters、mapActions这几个函数功能的实现,当然还有其他一些辅助函数或工具函数就留下自己去看吧。

到此,vuex的源码解析就结束吧。不难,我们再整理下要点: