前言
當一個元件要獲取多個 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 的解讀算告一段落。