Vuex鲜为人知的8个秘密

186 阅读3分钟

Vuex背后的基本思想

通过定义和隔离状态管理中的各种概念,并通过强制规则维持视图和状态间的独立性,让代码变得更结构化且易维护。

Vuex与全局对象的不同点

  1. Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。
  2. 你不能直接改变 store 中的状态。改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。这样使得我们可以方便地跟踪每一个状态的变化。

State 单一状态树

Vuex 使用单一状态树:用一个对象就包含了全部的应用层级状态。这也意味着,每个应用将仅仅包含一个 store 实例。单一状态树让我们能够直接地定位任一特定的状态片段,在调试的过程中也能轻易地取得整个当前应用状态的快照。

单状态树和模块化并不冲突

为何Mutations中只能放同步任务

看这个例子,api表示发请求

mutations: {
  someMutation (state) {
    api.callAsyncMethod(() => {
      state.count++
    })
  }
}
  1. 首先,devtools 能记录每一条 mutation 的基础是:捕捉到前一状态和后一状态的快照
  2. 现在,我们要在异步函数的回调中修改state中的数据。
  3. 然而,devtools 无法记录这一次的mutation,因为当 mutation 触发的时候,异步函数回调还没有被调用。
  4. 实质上,任何在回调函数中进行的状态的改变都是不可追踪的。

Action的context对象

Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象,因此有以下操作:

  1. 使用 context.commit 调用 mutations 中的函数
  2. 使用 context.state 访问state中的数据
  3. 使用 context.getters 访问getters中的数据

然而,context 对象并不是 store 实例本身

如何组合多个Action

Action 通常是异步的,那么如何知道 action 什么时候结束呢?

更重要的是,我们如何才能组合多个 action,以处理更加复杂的异步流程?

首先,你需要明白 store.dispatch 可以处理被触发的 action 的处理函数返回的 Promise,并且 store.dispatch 仍旧返回 Promise:

actions: {
  actionA ({ commit }) {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        commit('someMutation')
        resolve()
      }, 1000)
    })
  }
}

现在你可以:

store.dispatch('actionA').then(() => {
  // ...
})

在另外一个 action 中也可以:

actions: {
  // ...
  actionB ({ dispatch, commit }) {
    return dispatch('actionA').then(() => {
      commit('someOtherMutation')
    })
  }
}

最后,利用async/await组合action。 一个 store.dispatch 在不同模块中可以触发多个 action 函数。在这种情况下,只有当所有触发函数完成后,返回的 Promise 才会执行。

// 假设 getData() 和 getOtherData() 返回的是 Promise

actions: {
  async actionA ({ commit }) {
    commit('gotData', await getData())
  },
  async actionB ({ dispatch, commit }) {
    await dispatch('actionA') // 等待 actionA 完成
    commit('gotOtherData', await getOtherData())
  }
}

getters具有缓存

Vuex 允许我们在 store 中定义“getter”(可以认为是 store 的计算属性)

就像计算属性一样,getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算

三个必须遵守的规则

  1. 应用层级的状态应该集中到单个 store 对象中。
  2. 提交 mutation 是更改状态的唯一方法,并且这个过程是同步的。
  3. 异步逻辑都应该封装到 action 里面。