vuex辅助函数

78 阅读1分钟

vuex是一个依赖于vue的状态管理工具,在项目中也不是必须的,但当项目足够大,一般都会用到,因为它的确解决了不少问题:

  • 父子组件可以通过props来传递参数,而兄弟组件呢?在遵循单向数据流的设计原则下,vuex可以实现
  • 可以作为一个全局响应式变量,如果定义一个全局变量,不仅可能造成污染,也无法实现响应式,这种情况下vuex就特别合适了

vuex的核心是store,里面储存的都是响应式属性,并且不能直接修改store中的状态,必须通过显示的提交(commit)对应的mutation来完成,只有这一种方式。

辅助函数

state

在项目中使用state:

const counter = {
  template: `<div>{{ count }}</div>`,
  computed: {
    count () {
      return this.$store.state.count // count状态
    }
  }
}

如果当某个组件需要用到多个state,使用枚举的方式那就需要在computed中罗列出多个,这样做可以,但看起来很不优雅和冗余,这个时候就可以使用辅助函数mapState

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

getter

getter相当于store的计算属性,也就是说在业务中,状态可能不是我们直接需要的对象,而需要额外的处理,避免每次都去处理相同的逻辑,就用getter来封装:

computed: {
  // 我们可能仅需要任务已完成的数量
  doneTodosCount () {
    return this.$store.state.todos.filter(todo => todo.done).length
  }
}

对于其辅助函数,和mapState的意义相同,也是避免冗余的属性重复编写:

import { mapGetters } from 'vuex'
export default {
  // ...
  computed: {
    ...mapGetters([
      'doneTodosCount', // 把this.doneTodosCount映射为this.$store.getters.doneTodosCount
      // ...
    ])
  }
}

源码实现

vuex代码src/index.js路径下导出了辅助函数方法:

image.png

接着往下看helpers.js文件:

我们以mapState方法看看,其实代码很简单,这个函数的主要作用就是把多个state组成的mapState拆分成一个对象,里面包含了所有定义的state

export const mapState = normalizeNamespace((namespace, states) => {
  const res = {}
  // mapState必须是数组或对象,否则会报错
  if (__DEV__ && !isValidMap(states)) {
    console.error('[vuex] mapState: mapper parameter must be either an Array or an Object')
  }
  normalizeMap(states).forEach(({ key, val }) => {
    res[key] = function mappedState () {
      let state = this.$store.state
      let getters = this.$store.getters
      // 处理modules
      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
})