Vue学习笔记(4):Vuex基础
vuex的学习笔记
基本使用
最简单的使用方式:
1 | import Vue from 'vue' |
这样可以通过调用这个store使用vuex功能
1 | store.commit('increment') |
State
Vuex 使用单一状态树——是的,用一个对象就包含了全部的应用层级状态。至此它便作为一个“唯一数据源 (SSOT (opens new window))”而存在。这也意味着,每个应用将仅仅包含一个 store 实例。单一状态树让我们能够直接地定位任一特定的状态片段,在调试的过程中也能轻易地取得整个当前应用状态的快照。
官网如是说道
在组件中获取Vuex状态
首先需要创建vue实例时将store绑定,这样就可以在所有的子组件通过 this.$store
调用
1 | // 创建一个 Counter 组件 |
1 | const app = new Vue({ |
mapState 辅助函数
演示:
1 | // 在单独构建的版本中辅助函数为 Vuex.mapState |
当映射的计算属性的名称与 state 的子节点名称相同时,我们也可以给 mapState 传一个字符串数组:
1 | computed: mapState([ |
使用对象展开运算符混合自定义计算属性
演示:
1 | computed: { |
Getters
有时候我们需要从 store 中的 state 中派生出一些状态,例如对列表进行过滤并计数,而且可能多个组件都需要用到,我们要么复制这个函数,或者抽取到一个共享函数然后在多处导入它——无论哪种方式都不是很理想。
那么就在store中定义getter吧(可以认为是 store 的计算属性)。就像计算属性一样,getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。
演示:
1 | const store = new Vuex.Store({ |
然后就可以以属性的形式访问这些值:
1 | store.getters.doneTodos |
Getter 也可以接受其他 getter 作为第二个参数:
1 | getters: { |
一样的方法调用:
1 | store.getters.doneTodosCount |
注意,getter 在通过属性访问时是作为 Vue 的响应式系统的一部分缓存其中的。
通过方法访问
你也可以通过让 getter 返回一个函数,来实现给 getter 传参。在你对 store 里的数组进行查询时非常有用。
1 | getters: { |
调用:
1 | store.getters.getTodoById(2) |
注意,getter 在通过方法访问时,每次都会去进行调用,而不会缓存结果。
mapGetters 辅助函数
mapGetters 辅助函数仅仅是将 store 中的 getter 映射到局部计算属性:
1 | import { mapGetters } from 'vuex' |
如果你想将一个 getter 属性另取一个名字,使用对象形式:
1 | ...mapGetters({ |
Mutation
Mutation 作用是用于改变store里的值,只能同步提交。
更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数:
1 | const store = new Vuex.Store({ |
调用这个方式的途径是以相应的 type 调用 store.commit 方法:
1 | store.commit('increment') |
提交载荷(Payload)
可以向 store.commit 传入额外的参数,即 mutation 的 载荷(payload):
1 | // ... |
在大多数情况下,载荷应该是一个对象,这样可以包含多个字段并且记录的 mutation 会更易读:
1 | // ... |
对象风格的提交方式
提交 mutation 的另一种方式是直接使用包含 type 属性的对象:
1 | store.commit({ |
当使用对象风格的提交方式,整个对象都作为载荷传给 mutation 函数,因此 handler 保持不变:
1 | mutations: { |
Mutation 需遵守 Vue 的响应规则
- 最好提前在你的 store 中初始化好所有所需属性。
- 当需要在对象上添加新属性时,你应该
- 使用 Vue.set(obj, ‘newProp’, 123), 或者
- 以新对象替换老对象。(可以使用展开运算符,将新属性合并成一个新对象)
在组件中提交 Mutation
你可以在组件中使用 this.$store.commit(‘xxx’) 提交 mutation,或者使用 mapMutations 辅助函数将组件中的 methods 映射为 store.commit 调用(需要在根节点注入 store)。
1 | import { mapMutations } from 'vuex' |
Action
Action 类似于 mutation,不同在于:
- Action 提交的是 mutation,而不是直接变更状态。
- Action 可以包含任意异步操作。
1 | const store = new Vuex.Store({ |
Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象,因此可以调用 context.commit 提交一个 mutation,或者通过 context.state 和 context.getters 来获取 state 和 getters。
分发 Action
Action 的分发通过 store.dispatch
方法触发: store.dispatch('increment')
因为Action可以执行异步代码,比如这样:
1 | actions: { |
Actions 支持同样的载荷方式和对象方式进行分发:
1 | // 以载荷形式分发 |
来看一个更加实际的购物车示例,涉及到调用异步 API 和分发多重 mutation:
1 | actions: { |
在组件中分发 Action
在组件中使用 this.$store.dispatch(‘xxx’) 分发 action,或者使用 mapActions 辅助函数将组件的 methods 映射为 store.dispatch 调用(需要先在根节点注入 store):
1 | import { mapActions } from 'vuex' |
组合 Action
因为action可以异步执行,所以可以组合多个action。而且dispatch可以返回一个Promise,所以可以这样写:
1 | actions: { |
在另外一个 action 中也可以:
1 | actions: { |
使用优雅的async await来改写:
1 | actions: { |