遲來的vuex源碼筆記,落後大佬一大截

vuex 輔助函數-mapState

vuex提供了四個經常使用的輔助函數vue

  1. mapState
  2. mapGetters
  3. mapActions
  4. mapMutations

mapState

mapState(namespace?: string, map: Array<string> | Object<string | function>): Objectvuex

  1. 爲組件建立計算屬性以返回 Vuex store 中的狀態
  2. 第一個參數是可選的,能夠是一個命名空間字符串,對象形式的第二個參數的成員能夠是一個函數。
computed: mapState({
    // 箭頭函數可以使代碼更簡練
    count: state => state.count,

    // 傳字符串參數 'count' 等同於 `state => state.count`
    countAlias: 'count',

    // 爲了可以使用 `this` 獲取局部狀態,必須使用常規函數
    countPlusLocalState (state) {
      return state.count + this.localCount
    }
})
複製代碼

看下源代碼(vuex\src\helpers.js):數組

export const mapState = normalizeNamespace((namespace, states) => {
  const res = {}
  normalizeMap(states).forEach(({ key, val }) => {
    res[key] = function mappedState () {
      let state = this.$store.state
      let getters = this.$store.getters
      if (namespace) {
        const module = getModuleByNamespace(this.$store, 'mapState', namespace)
        if (!module) {
          return
        }
        state = module.context.state
        getters = module.context.getters
      }
      return typeof val === 'function'
        ? val.call(this, state, getters)
        : state[val]
    }
    // mark vuex getter for devtools
    res[key].vuex = true
  })
  return res
})
function normalizeNamespace (fn) {
  return (namespace, map) => {
    if (typeof namespace !== 'string') {
      map = namespace
      namespace = ''
    } else if (namespace.charAt(namespace.length - 1) !== '/') {
      namespace += '/'
    }
    return fn(namespace, map)
  }
}
function normalizeMap (map) {
  if (!isValidMap(map)) {
    return []
  }
  return Array.isArray(map)
    ? map.map(key => ({ key, val: key }))
    : Object.keys(map).map(key => ({ key, val: map[key] }))
}
複製代碼

mapState是經過normalizeNamespace返回的函數,他接收了參數:namespace,map,namespace是命名空間,map是具體的對象,其實按照官網說明namespace是能夠不傳入的.而調用了normalizeNamespace以後,就是將map做爲state傳入,而後調用normalizeMap,將map變成以{key,val:key}這樣的格式的數組。構建完成以後。執行循環,而後將key,以及valmappedState做爲value存入到resmarkdown

mappedState

res[key] = function mappedState () {
      let state = this.$store.state
      let getters = this.$store.getters
      if (namespace) {
        const module = getModuleByNamespace(this.$store, 'mapState', namespace)
        if (!module) {
          return
        }
        state = module.context.state
        getters = module.context.getters
      }
      return typeof val === 'function'
        ? val.call(this, state, getters)
        : state[val]
    }
複製代碼

首先獲取了$store.state$store.gettersapp

若是命名空間的時候函數

而後根據命名空間名,獲取了模塊,獲取模塊對應的stategetters。而後經過判斷咱們書寫的mapState的第二個參數,是函數的話,就執行這個函數,將stategetters傳入,反之就返回state[val]this

實例:spa

// 基於屬性的訪問
mapState({
    searchInput: state => state.yourModuleName.searchInput,
})

// 使用namespace訪問
...mapState('yourModuleName',[
  'searchInput',
])
複製代碼

mapGetters

  • mapGetters(namespace?: string, map: Array<string> | Object<string>): Object

爲組件建立計算屬性以返回 getter 的返回值。 第一個參數是可選的,能夠是一個命名空間字符串code

官方實例:orm

// map爲Array
computed: {
  // 使用對象展開運算符將 getter 混入 computed 對象中
    ...mapGetters([
      'doneTodosCount',
      'anotherGetter',
      // ...
    ])
}

// map爲Object
...mapGetters({
  // 把 `this.doneCount` 映射爲 `this.$store.getters.doneTodosCount`
  doneCount: 'doneTodosCount'
})

複製代碼

看一下源碼實現

export const mapGetters = normalizeNamespace((namespace, getters) => {
  const res = {}
  normalizeMap(getters).forEach(({ key, val }) => {
    // The namespace has been mutated by normalizeNamespace
    val = namespace + val
    res[key] = function mappedGetter () {
      if (namespace && !getModuleByNamespace(this.$store, 'mapGetters', namespace)) {
        return
      }
      return this.$store.getters[val]
    }
    // mark vuex getter for devtools
    res[key].vuex = true
  })
  return res
})
複製代碼

mapState不一樣的地方是mapGetters採用的是在this.$store.getters取得值

mapMutations

示例:

methods: {
    ...mapMutations([
      'increment', // 將 `this.increment()` 映射爲 `this.$store.commit('increment')`

      // `mapMutations` 也支持載荷:
      'incrementBy' // 將 `this.incrementBy(amount)` 映射爲 `this.$store.commit('incrementBy', amount)`
    ]),
    ...mapMutations({
        account: (commit, account) => {
                commit("account", account)
        },
      }),
    ...mapMutations({
      add: 'increment' // 將 `this.add()` 映射爲 `this.$store.commit('increment')`
    })
  }
複製代碼

mapMutations(namespace?: string, map: Array<string> | Object<string | function>): Object

  • 建立組件方法提交 mutation
  1. 第一個參數是可選的,能夠是一個命名空間字符串
  2. 對象形式的第二個參數的成員能夠是一個函數。function(commit: function, ...args: any[])
export const mapMutations = normalizeNamespace((namespace, mutations) => {
  const res = {}
  normalizeMap(mutations).forEach(({ key, val }) => {
    res[key] = function mappedMutation (...args) {
      // Get the commit method from store
      let commit = this.$store.commit
      if (namespace) {
        const module = getModuleByNamespace(this.$store, 'mapMutations', namespace)
        if (!module) {
          return
        }
        commit = module.context.commit
      }
      return typeof val === 'function'
        ? val.apply(this, [commit].concat(args))
        : commit.apply(this.$store, [val].concat(args))
    }
  })
  return res
})
複製代碼
  1. 首先將全部得mutaions獲取到{key,val:key}相似於這樣得格式得數組,進行循環
  2. 而後從this.$store獲取到commit這個方法,若是是一個命名空間的module,那麼就會經過getModuleByNamespace獲取對應的module
  3. 最後執行對應store內的commit
  • 若是valfunction(示例第二種狀況),傳入的是 2 個值,一個commit,一個爲參數,因此這就是爲何能獲取到commit同時將本身的載荷payload傳入的緣由
  • 若是不是function那麼走的就是commit.apply(this.$store, [val].concat(args)),而後提交改變了state

mapActions

示例:

// Array
 ...mapActions([
      'increment', // 將 `this.increment()` 映射爲 `this.$store.dispatch('increment')`

      // `mapActions` 也支持載荷:
      'incrementBy' // 將 `this.incrementBy(amount)` 映射爲 `this.$store.dispatch('incrementBy', amount)`
    ]),
    // Object
    ...mapActions({
      add: 'increment' // 將 `this.add()` 映射爲 `this.$store.dispatch('increment')`
    })
複製代碼

看下源碼實現:

export const mapActions = normalizeNamespace((namespace, actions) => {
  const res = {}
  normalizeMap(actions).forEach(({ key, val }) => {
    res[key] = function mappedAction (...args) {
      // get dispatch function from store
      let dispatch = this.$store.dispatch
      if (namespace) {
        const module = getModuleByNamespace(this.$store, 'mapActions', namespace)
        if (!module) {
          return
        }
        dispatch = module.context.dispatch
      }
      return typeof val === 'function'
        ? val.apply(this, [dispatch].concat(args))
        : dispatch.apply(this.$store, [val].concat(args))
    }
  })
  return res
})

複製代碼
  1. 咱們知道actions是用來派發mutations的,因此確定是須要一個dispatch,能夠來自於也能夠是子模塊
  2. 在這裏判斷跟mutation是同樣的,也是分爲fun和其餘類型,做爲處理
相關文章
相關標籤/搜索