前言

当一个组件要获取多个 state 的时候,声明计算属性就会变得重复和冗余了。我们可以使用到辅助函数 mapState 来更快更简洁地生成计算属性。

所以我们得清楚,mapState 的作用就是帮我们把一个对象或数组里的值转化成计算属性的写法。同理,其它的辅助函数也是大同小异,只要知道了 mapState 的实现,其它的也基本都明白了。

注:本次阅读的是 vuex 的 2.0.0 版本,源码请戳 这里

准备

解读前,我们需要熟悉一些方法的使用:

解读

先来 mapState 的使用方式:

import { mapState } from 'vuex'

export default {
computed: mapState([
// 映射 this.count 为 store.state.count
'count'
])
}

mapState 返回一个对象,我们知道以上的代码最后会变成这样:

import { mapState } from 'vuex'

export default {
computed: {
count () {
return this.$store.state.count
}
}
}

那么我们就来开始看看 mapState 做了什么处理。

还是从 vuex 的 APi 看起,打开 src/index.js 文件,最下面的代码中可以看到 vuex 暴露出的 mapState:

export default {
Store,
install,
mapState,
mapMutations,
mapGetters,
mapActions
}

定位后可以找到最前面的引入:

import { mapState, mapMutations, mapGetters, mapActions } from './helpers'

打开 src/helpers.js 文件,里面便有 mapState 的实现。

normalizeMap

想知道 mapStat 这个方法的实现,还得知道里面的 normalizeMap 这个方法的实现。定位找到 normalizeMap 方法:

function normalizeMap (map) {
return Array.isArray(map)
? map.map(key => ({ key, val: key }))
: Object.keys(map).map(key => ({ key, val: map[key] }))
}

这个方法主要是格式化 mapState 传进来的 states 参数。我们会知道 states 参数会是两种形式,一种是以数组的方式传入,另一种则是以对象的方法传入。

例如以下代码:

// 以数组的方式传入
mapState([
'count',
'add'
]) // 以对象的方法传入
mapState({
count: state => state.count,
countAlias: 'count'
})

经过 normalizeMap 方法处理后会变成这样:

// 以数组的方式传入
[
{
key: 'count',
val: 'count'
},
{
key: 'add',
val: 'add'
}
] // 以对象的方法传入
[
{
key: count,
val: state => state.count
},
{
key: countAlias,
val: 'count'
}
]

mapState

知道了 normalizeMap 方法的实现,再回头看 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 格式化后返回的数组进行遍历,拼接一个符合 computed 的对象(需有返回值)。

对 normalizeMap 返回数组的对象里的 val 有两个判断。如果不是函数,直接查找 this.$store.state[val] 返回 state。如果是函数,则需要使用 call 将 val 这个函数的 this 指向 vue 实例,然后将 state 和 getters 传入,最后执行 val 函数。

val 函数

如果 val 是函数,可能有点难理解,举个例子,传入的参数可能是这样子的:

computed: mapState({
countPlusLocalState (state) {
return state.count + this.localCount
}
})

经过 normalizeMap 方法后返回的对象为:

[
{
key: 'countPlusLocalState',
val: function (state) {
return state.count + this.localCount
}
}
]

再经过 mapState 最后返回的 res 是。这里会将 val 函数执行一遍,将函数的返回值 return 出来。

{
countPlusLocalState: function mappedState () {
return this.$store.state.count + this.localCount
}
}

至此,mapState 的解读已经结束了。另外,mapState 还经常使用到 es6 的扩展运算符,这个不是 vuex 的实现,而是 es6 的一个新特性:

computed: {
localComputed () { /* ... */ }, // 使用对象展开运算符将此对象混入到外部对象中
...mapState({
// ...
})
}

例外需要注意,如果要使用 es6 的扩展运算符,还需要引入一个 babel 包:babel-plugin-transform-object-rest-spread

总结

mapState 的代码不多,主要的功能就是将传入的数组或对象转成 computed 计算属性能够识别的代码。比较难理解的就是对象带有函数的返回值有点绕,多看几遍理解理解。

mapState 里面的代码实现非常的简洁精湛,主要用到了 js 的一些内置函数做处理,如果是我,估计会一直写 for 循环实现吧哈哈,从中收获到不少知识的。至此,vuex 的解读算告一段落。

vuex 源码:深入 vuex 之辅助函数 mapState的更多相关文章

  1. vuex 源码分析(六) 辅助函数 详解

    对于state.getter.mutation.action来说,如果每次使用的时候都用this.$store.state.this.$store.getter等引用,会比较麻烦,代码也重复和冗余,我 ...

  2. VueX源码分析(2)

    VueX源码分析(2) 剩余内容 /module /plugins helpers.js store.js helpers要从底部开始分析比较好.也即先从辅助函数开始再分析那4个map函数mapSta ...

  3. VueX源码分析(5)

    VueX源码分析(5) 最终也是最重要的store.js,该文件主要涉及的内容如下: Store类 genericSubscribe函数 resetStore函数 resetStoreVM函数 ins ...

  4. VueX源码分析(4)

    VueX源码分析(4) /module store.js /module/module.js import { forEachValue } from '../util' // Base data s ...

  5. VueX源码分析(1)

    VueX源码分析(1) 文件架构如下 /module /plugins helpers.js index.esm.js index.js store.js util.js util.js 先从最简单的 ...

  6. 逐行粒度的vuex源码分析

    vuex源码分析 了解vuex 什么是vuex vuex是一个为vue进行统一状态管理的状态管理器,主要分为state, getters, mutations, actions几个部分,vue组件基于 ...

  7. Vuex 源码学习(一)

    (一)Vuex 是什么? Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式.它采用集中式存储管理应用的所有组件的状态, 并以相应的规则保证状态以一种可预测的方式发生变化. —— 来自 V ...

  8. vuex源码 安装依赖问题

    今天下载vuex源码时 安装依赖出现以下问题 > chromedriver@2.32.3 install /Users/bao/Desktop/vue-store/vuex/node_modul ...

  9. VueX源码分析(3)

    VueX源码分析(3) 还剩余 /module /plugins store.js /plugins/devtool.js const devtoolHook = typeof window !== ...

  10. 一张思维导图辅助你深入了解 Vue | Vue-Router | Vuex 源码架构

    1.前言 本文内容讲解的内容:一张思维导图辅助你深入了解 Vue | Vue-Router | Vuex 源码架构. 项目地址:https://github.com/biaochenxuying/vu ...

随机推荐

  1. Golang匿名函数

    概念所谓匿名函数,就是没有名字的函数匿名函数的两种使用方式一.在定义匿名函数的时候就可以直接使用(这种方式只使用一次) package main import ( "fmt" ) ...

  2. P2590 [ZJOI2008]树的统计(树链剖分)

    P2590 [ZJOI2008]树的统计 虽然是入门树剖模板 但是我终于1A了(大哭) 懒得写啥了(逃 #include<iostream> #include<cstdio> ...

  3. c++ kafka 客户端rdkafka报Receive failed: Disconnected问题原因以及解决方法

    %3|1538976114.812|FAIL|rdkafka#producer-1| [thrd:kafka-server:9092/bootstrap]: kafka-server:9092/0: ...

  4. Codeforces 835F Roads in the Kingdom - 动态规划

    题目传送门 传送点I 传送点II 传送点III 题目大意 给定一颗基环树,要求删去其中一条边,使得剩下的图形是一棵树,并且最长路的长度最短,求最长路的最短长度. 路径可以分为两部分:跨过环 和 在树内 ...

  5. Codeforces Round #439 (Div. 2) Problem B (Codeforces 869B)

    Even if the world is full of counterfeits, I still regard it as wonderful. Pile up herbs and incense ...

  6. 向eclipse的JavaWeb项目中导入jar包

    一:      在你所需的jar包网站下载对应的jar包.如org.apache.commons.lang.jar. 二:复制粘贴到该JavaWeb的WEB-INF目录下的lib目录下,如: 三:右键 ...

  7. topcoder srm 390 div1

    problem1 link 记录一个模$k$之后的值是否出现过,出现过则出现循环,无解:否则最多$k$ 次一定能出现0. import java.util.*; import java.math.*; ...

  8. c++string,常见用法总结

    #include<iostream> #include<string> using namespace std; int main() { //创建对象,及初始化 string ...

  9. 自动化测试系列:Selenium UI自动化解决iframe定位问题

      更多原创测试技术文章同步更新到微信公众号 :三国测,敬请扫码关注个人的微信号,感谢! 原文链接:http://www.cnblogs.com/zishi/p/6735116.html 一个阴雨霏霏 ...

  10. java 动态代理总结

    首先:定义一个接口// 只能是一个接口 例: package DongTai; public interface dongtai { public void show(); } 接着:定义一个被代理类 ...