现在将 vuex 整合到我们的 vue-complex 应用中
npm install vuex -S
有关于vuex的详细介绍 ,可以看看官方文档,这里仅仅是简单概括。
1.为什么要用Vuex
我们知道,在vue应用中,组件的状态都是单向传递的:从父组件--> 子组件。而想将状态从子组件传递到父组件,则需要通过回调函数来实现。这种做法在简单的应用中确实是可行的,但是当应用变得越来越复杂,状态就变得越来越难维护。而vuex就是为了解决这样的问题。
Vuex的做法很简单,把组件的共享状态抽取出来,以一个全局单例模式管理。当其它组件需要用到这个共享状态的时候,直接去 这个单利对象里面获取就可以了,统一管理,方便了很多。

下面的是 Vuex 背后的基本思想,借鉴了 Flux、Redux、和 The Elm Architecture。与其他模式不同的是,Vuex 是专门为 Vue.js 设计的状态管理库,以利用 Vue.js 的细粒度数据响应机制来进行高效的状态更新。

每一个 Vuex 应用的核心就是 store(仓库)。“store”基本上就是一个容器,它包含着你的应用中大部分的状态 (state)。Vuex 和单纯的全局对象有以下两点不同:
①Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。
②不能直接改变 store 中的状态。改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。这样使得我们可以方便地跟踪每一个状态的变化,从而让我们能够实现一些工具帮助我们更好地了解我们的应用。
2.使用Vuex
在模块化构建系统中,首先需要
Vue.use(Vuex)
然后,初始化一个store

通过 store.state 来获取状态对象,以及通过 store.commit 方法修改状态

3.state
state就是状态,也可以认为就是一些数据,这就是Vuex需要管理的内容。比如B组件需要用到A组件种的一些状态,A组件可以先把自己的一些状态放到store里面,然后B组件直接从store里面获取。从 store 实例中读取状态最简单的方法就是在计算属性中返回某个状态

Vuex 通过 store 选项,提供了一种机制将状态从根组件“注入”到每一个子组件中

当一个组件需要获取多个状态时候,将这些状态都声明为计算属性会有些重复和冗余,这时候可以使用vuex提供的mapState函数来简化书写:

4.Getter
Vuex 允许我们在 store 中定义“getter”(可以认为是 store 的计算属性)。就像计算属性一样,getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。Getter 接受 state 作为其第一个参数:

访问的时候也很方便: store.getters.doneTodos
也可以通过让 getter 返回一个函数,来实现给 getter 传参。在你对 store 里的数组进行查询时非常有用

vuex提供了辅助函数mapGetters将 store 中的 getter 映射到局部计算属性

如果你想将一个 getter 属性另取一个名字,使用对象形式:

5.Mutation
这个就是用来修改store里面的状态的,而且也只能通过提交 mutation 来修改store里面的状态。

当触发一个类型为 increment 的 mutation 时,调用此函数:store.commit('increment') 也可以传参数:

提交 mutation 的另一种方式是直接使用包含 type 属性的对象:

vuex提供了辅助函数 mapMutations 将组件中的 methods 映射为 store.commit 调用。

一条重要的原则就是要记住 mutation 必须是同步函数!所以,当调用了两个包含异步回调的 mutation 来改变状态,你怎么知道什么时候回调和哪个先回调呢?这就是为什么我们要区分这两个概念。在 Vuex 中,mutation 都是同步事务。
6.Action
Action和 mutation 很像,不同的是:Action 提交的是 mutation,而不是直接变更状态;Action 可以包含任意异步操作。

Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象,因此你可以调用 context.commit 提交一个 mutation,或者通过 context.state 和 context.getters 来获取 state 和 getters。
实践中,我们会经常用到 ES2015 的参数解构来简化代码

Action 通过 store.dispatch 方法触发:store.dispatch('increment')
Actions 支持同样的载荷方式和对象方式进行分发:


你在组件中使用 this.$store.dispatch('xxx') 分发 action,或者使用 mapActions 辅助函数将组件的 methods 映射为 store.dispatch 调用(需要先在根节点注入 store):

Action 通常是异步的,那么如何知道 action 什么时候结束呢?更重要的是,我们如何才能组合多个 action,以处理更加复杂的异步流程?
首先,你需要明白 store.dispatch 可以处理被触发的 action 的处理函数返回的 Promise,并且 store.dispatch 仍旧返回 Promise:

现在你可以:

在另外一个 action 中也可以:

最后,如果我们利用 async / await,我们可以如下组合 action:

一个 store.dispatch 在不同模块中可以触发多个 action 函数。在这种情况下,只有当所有触发函数完成后,返回的 Promise 才会执行。
7.Module
Module的内容比较多,不多说,直接看看官网的文档。
由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割:

①模块的局部状态
对于模块内部的 mutation 和 getter,接收的第一个参数是模块的局部状态对象

同样,对于模块内部的 action,局部状态通过 context.state 暴露出来,根节点状态则为 context.rootState

对于模块内部的 getter,根节点状态会作为第三个参数暴露出来

②命名空间
默认情况下,模块内部的 action、mutation 和 getter 是注册在全局命名空间的——这样使得多个模块能够对同一 mutation 或 action 作出响应。如果希望你的模块具有更高的封装度和复用性,你可以通过添加 namespaced: true 的方式使其成为命名空间模块。当模块被注册后,它的所有 getter、action 及 mutation 都会自动根据模块注册的路径调整命名。例如:

网友评论