vuex知识总结

Authors
  • avatar
    Name
    小明&小艺
    Twitter

状态管理

一个状态管理的库,会涉及到这三部分:state、view、actions。可以知道的是:

  • state 会影响 view
  • view 会影响 action

但会影响 state 的是什么呢?action,action 可能是单一的或者是来自于多个视图的。

vuex 的特点是把数据单独隔离,形成一棵树状图。单独隔离就意味着它有自己的生态系统。输入和输出,其中 action 作为数据的输入,state 作为数据的输出。如下图:

image

图中有一个奇怪的地方,多了一个 mutations,而且与 state 相连的是 mutations 而不是 actions。

vuex 里有这么一个规则:

只能在 mutaions 里修改 state,actions 不能直接修改 state

mutations 即变化,修改 state 的数据,而且只能是同步的,不能存在异步的操作。如果需要异步怎么办呢?把异步操作放在 actions 里,拿到数据再通过 mutations 同步处理。

vuex 做的其实是把职权明确了,责任细分了。所以它文档里也说,小系统可以不用。状态数据少,没有细分的必要。

使用方法

  • Action 通过 store.dispatch 方法触发
  • Mutations 通过 store.commit 方法触发
// 触发动作
actions: {
  incrementAsync ({ commit }) {
    setTimeout(() => {
      commit('increment')
    }, 1000)
  }
}
store.dispatch('increment')
// 触发变化
mutations: {
  increment (state, n) {
    state.count += n
  }
}
store.commit('increment', 10)

为了更方便地读取 state 里面的数据,其还提高了一些维护的方法:

  • getters 就像计算属性一样,getters 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算
  • mapGetters 将 store 中的 getters 映射到局部计算属性
  • mapMutations 将组件中的 methods 映射为 store.commit 调用
  • mapActions 将组件的 methods 映射为 store.dispatch 调用
methods: {
    ...mapMutations([
      'increment' // 映射 this.increment() 为 this.$store.commit('increment')
    ]),
    ...mapMutations({
      add: 'increment' // 映射 this.add() 为 this.$store.commit('increment')
    })
    ...mapActions([
      'increment' // 映射 this.increment() 为 this.$store.dispatch('increment')
    ]),
    ...mapActions({
      add: 'increment' // 映射 this.add() 为 this.$store.dispatch('increment')
    })
}

getter 既然是会缓存的,那怎么带参数呢?github 里有人建议这样写:

getters: {
    getListByVal: (state) => (val) => {
        return state.list.find(item => item.value = val)
    }
}

模块划分

当状态比较多的时候,vuex 支持模块划分,可以通过模块划分,让 store 树简化一下。每个模块拥有自己的 state、mutation、action、getter。

  • 对于模块内部的 mutation 和 getter,接收的第一个参数是模块的局部状态对象
  • getter 根节点状态会作为第三个参数暴露出来
  • 内部的 action,局部状态通过 context.state 暴露出来, 根节点状态则为 context.rootState
const moduleA = {
  state: { ... },
  mutations: { ... },
  actions: { ... },
  getters: { ... }
}

const moduleB = {
  state: { ... },
  mutations: { ... },
  actions: { ... }
}

const store = new Vuex.Store({
  modules: {
    a: moduleA,
    b: moduleB
  }
})

store.state.a // -> moduleA 的状态
store.state.b // -> moduleB 的状态