迟来的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和其余类型,做为处理
相关文章
相关标签/搜索