vuex 中关于 mapState 的作用
辅助函数
Vuex 除了提供我们 Store 对象外,还对外提供了一系列的辅助函数,方便我们在代码中使用 Vuex,提供了操作 store 的各种属性的一系列语法糖,下面我们来一起看一下:
mapState
mapState 工具函数会将 store 中的 state 映射到局部计算属性中。为了更好理解它的实现,先来看一下它的使用示例:
// vuex 提供了独立的构建工具函数 Vuex.mapState import { mapState } from 'vuex' export default { // ... computed: mapState({ // 箭头函数可以让代码非常简洁 count: state => state.count, // 传入字符串 'count' 等同于 `state => state.count` countAlias: 'count', // 想访问局部状态,就必须借助于一个普通函数,函数中使用 `this` 获取局部状态 countPlusLocalState (state) { return state.count + this.localCount } }) }
当计算属性名称和状态子树名称对应相同时,我们可以向 mapState 工具函数传入一个字符串数组
computed: mapState([ // 映射 this.count 到 this.$store.state.count 'count' ])
即 等价于
computed: mapState([ // 传入字符串 'count' 等同于 `state => state.count` count: 'count', ])
即 等价于
computed: mapState([ // 映射 this.count 到 this.$store.state.count count: state => state.count, ])
通过例子我们可以直观的看到,mapState函数可以接受一个对象,也可以接收一个数组,那它底层到底干了什么事呢,我们一起来看一下源码这个函数的定义:
export function mapState (states) { const res = {} normalizeMap(states).forEach(({ key, val }) => { res[key] = function mappedState () { return typeof val === 'function' ? val.call(this, this.$store.state, this.$store.getters) : this.$store.state[val] } }) return res }
函数首先对传入的参数调用 normalizeMap 方法,我们来看一下这个函数的定义:
function normalizeMap (map) { return Array.isArray(map) ? map.map(key => ({ key, val: key })) : Object.keys(map).map(key => ({ key, val: map[key] })) }
这个方法判断参数 map 是否为数组,如果是数组,则调用数组的 map 方法,把数组的每个元素转换成一个 {key, val: key}的对象;否则传入的 map 就是一个对象(从 mapState 的使用场景来看,传入的参数不是数组就是对象),我们调用 Object.keys 方法遍历这个 map 对象的 key,把数组的每个 key 都转换成一个 {key, val: key}的对象。最后我们把这个对象数组作为 normalizeMap 的返回值。
回到 mapState 函数,在调用了 normalizeMap 函数后,把传入的 states 转换成由 {key, val} 对象构成的数组,接着调用 forEach 方法遍历这个数组,构造一个新的对象,这个新对象每个元素都返回一个新的函数 mappedState,函数对 val 的类型判断,如果 val 是一个函数,则直接调用这个 val 函数,把当前 store 上的 state 和 getters 作为参数,返回值作为 mappedState 的返回值;否则直接把 this.$store.state[val] 作为 mappedState 的返回值。
那么为何 mapState 函数的返回值是这样一个对象呢,因为 mapState 的作用是把全局的 state 和 getters 映射到当前组件的 computed 计算属性中,我们知道在 Vue 中 每个计算属性都是一个函数。
为了更加直观地说明,回到刚才的例子:
import { mapState } from 'vuex' export default { // ... computed: mapState({ // 箭头函数可以让代码非常简洁 count: state => state.count, // 传入字符串 'count' 等同于 `state => state.count` countAlias: 'count', // 想访问局部状态,就必须借助于一个普通函数,函数中使用 `this` 获取局部状态 countPlusLocalState (state) { return state.count + this.localCount } }) }
经过 mapState 函数调用后的结果,如下所示:
import { mapState } from 'vuex' export default { // ... computed: { count() { return this.$store.state.count }, countAlias() { return this.$store.state['count'] }, countPlusLocalState() { return this.$store.state.count + this.localCount } } }
我们再看一下 mapState 参数为数组的例子:
computed: mapState([ // 映射 this.count 到 this.$store.state.count 'count' ])
经过 mapState 函数调用后的结果,如下所示:
computed: { count() { return this.$store.state['count'] } }
.