vuex 源碼:深刻 vuex 之輔助函數 mapState

前言

當一個組件要獲取多個 state 的時候,聲明計算屬性就會變得重複和冗餘了。咱們可使用到輔助函數 mapState 來更快更簡潔地生成計算屬性。vue

因此咱們得清楚,mapState 的做用就是幫咱們把一個對象或數組裏的值轉化成計算屬性的寫法。同理,其它的輔助函數也是大同小異,只要知道了 mapState 的實現,其它的也基本都明白了。git

注:本次閱讀的是 vuex 的 2.0.0 版本,源碼請戳 這裏es6

準備

解讀前,咱們須要熟悉一些方法的使用:github

解讀

先來 mapState 的使用方式:vuex

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 作了什麼處理。babel

仍是從 vuex 的 APi 看起,打開 src/index.js 文件,最下面的代碼中能夠看到 vuex 暴露出的 mapState:app

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 的解讀算告一段落。

相關文章
相關標籤/搜索