Vuex
创建store
每一个Vuex应用的核心就是store(仓库):
- store本质上是一个容器,它包含着你的应用中大部分的状态(state);
Vuex和单纯的全局对象有什么区别呢?
第一:Vuex的状态存储是响应式的
- 当Vue组件从store中读取状态的时候,若store中的状态发生变化,那么相应的组件也会被更新;
第二:你不能直接改变store中的状态
- 改变store中的状态的唯一途径就显示提交 (commit) mutation;
- 这样使得我们可以方便的跟踪每一个状态的变化,从而让我们能够通过一些工具帮助我们更好的管理应用的状态;
使用步骤:
- 创建Store对象;
- 在app中通过插件安装;
状态管理
在开发中,我们会的应用程序需要处理各种各样的数据,这些数据需要保存在我们应用程序中的某一个位置,对于这些数据的管理我们就称之为是 状态管理。
在前面我们是如何管理自己的状态呢?
- 在Vue开发中,我们使用组件化的开发方式;
- 而在组件中我们定义data或者在setup中返回使用的数据,这些数据我们称之为state;
- 在模块template中我们可以使用这些数据,模块最终会被渲染成DOM,我们称之为View;
- 在模块中我们会产生一些行为事件,处理这些行为事件时,有可能会修改state,这些行为事件我们称之为actions;
state
单一状态树
Vuex 使用单一状态树:
- 用一个对象就包含了全部的应用层级的状态;
- 采用的是SSOT,Single Source of Truth,也可以翻译成单一数据源;
- 这也意味着,每个应用将仅仅包含一个 store 实例;
- 单状态树和模块化并不冲突,后面我们会讲到module的概念;
单一状态树的优势:
- 如果你的状态信息是保存到多个Store对象中的,那么之后的管理和维护等等都会变得特别困难;
- 所以Vuex也使用了单一状态树来管理应用层级的全部状态;
- 单一状态树能够让我们最直接的方式找到某个状态的片段,而且在之后的维护和调试过程中,也可以非常方便的管理和维护;
在 Vue 组件中获得 Vuex 状态
那么我们如何在 Vue 组件中展示状态呢?由于 Vuex 的状态存储是响应式的,从 store 实例中读取状态最简单的方法就是在计算属性中返回某个状态:
// 创建一个 Counter 组件
const Counter = {
template: `<div>{{ count }}</div>`,
computed: {
count () {
return store.state.count
}
}
}
但是,如果我们有很多个状态都需要获取话,可以使用mapState的辅助函数:
- mapState的方式一:对象类型;
- mapState的方式二:数组类型;
- 也可以使用展开运算符和来原有的computed混合在一起;
mapState辅助函数
optionsAPI mapState数组写法
对象写法 可自命名
compositionAPI写法 引入useStore
这样似乎太繁琐了,有没有更好的解决办法呢
是因为这里的mapState返回的是一个类似下面的函数,我们对mapState进行解构赋值后在页面上相当于直接取到函数
counter:function(){}
我们可以封装一个hooks
即可正常使用
getters
Getter 会暴露为 store.getters 对象,你可以以属性的形式访问这些值:
在index.js中
Getter 也可以接受其他 getter 作为第二个参数:
一言蔽之就是第二个参数可以引用其他的getters方法
getters中的函数本身,可以返回一个函数,那么在使用的地方相当于可以调用这个函数:可以通过让 getter 返回一个函数,来实现给 getter 传参。
如果我们需要多个getters,我们就需要在页面中写多个store.getters.xxx,有没有更好的解决办法呢? 当然,我们也可以用computed来做处理。可是我们又遇到了同样的问题,是不是太繁琐了呢?
同样的,我们用一个辅助函数来解决
mapGetters 辅助函数
mutation
提交载荷(Payload)
你可以向 store.commit 传入额外的参数,即 mutation 的载荷(payload) :
在大多数情况下,载荷应该是一个对象,这样可以包含多个字段并且记录的 mutation 会更易读:
提交 mutation 的另一种方式是直接使用包含 type 属性的对象:
使用常量替代 mutation 事件类型在各种 Flux 实现中是很常见的模式。这样可以使 linter 之类的工具发挥作用,同时把这些常量放在单独的文件中可以让你的代码合作者对整个 app 包含的 mutation 一目了然:
mapMutations辅助函数
你可以在组件中使用 this.$store.commit('xxx') 提交 mutation,或者使用 mapMutations 辅助函数将组件中的 methods 映射为 store.commit 调用(需要在根节点注入 store)。
在compositionAPI中,用法更加简单
action
Action 类似于 mutation,不同在于:
- Action 提交的是 mutation,而不是直接变更状态。
- Action 可以包含任意异步操作。
让我们来注册一个简单的 action:
Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象,因此你可以调用 context.commit 提交一个 mutation,或者通过 context.state 和 context.getters 来获取 state 和 getters。
分发 Action
Action 通过 store.dispatch 方法触发:
Actions 支持同样的载荷方式和对象方式进行分发:
mapActions辅助函数
与mutation的用法类似 同样的,action也有对应的辅助函数:
compositionAPI写法
Module
module的基本使用
什么是Module?
- 由于使用单一状态树,应用的所有状态会集中到一个比较大的对象,当应用变得非常复杂时,store 对象就有可能变得相当臃肿;
- 为了解决以上问题,Vuex 允许我们将 store 分割成模块(module);
- 每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块;
下面是一个实例:
home.js
user.js
index.js
在页面中使用
getters直接使用,但是会无法区分其模块
module的命名空间
如果希望你的模块具有更高的封装度和复用性,你可以通过添加 namespaced: true 的方式使其成为带命名空间的模块。当模块被注册后,它的所有 getter、action 及 mutation 都会自动根据模块注册的路径调整命名。
module修改或派发根组件
如果我们希望在action中修改root中的state,那么有如下的方式:
module的辅助函数
如果辅助函数有三种使用方法:
- 方式一:通过完整的模块空间名称来查找;
- 方式二:第一个参数传入模块空间名称,后面写上要使用的属性;
- 方式三:通过 createNamespacedHelpers 生成一个模块的辅助函数;
与前文类似的对象写法或数组写法是
写法三:createNamespacedHelpers
在compositionAPI中,
useGetters.js
useState.js