Vuex的核心概念
State
是Vuex用来存储数据的地方,存储在state中数据可以看做是当前应用的全局变量可以在当前应用的任何地方访问。
1.是
Vuex用来存储数据的地方,存储在state中数据可以看做是当前应用的全局变量可以在当前应用的任何地方访问。2.在开发中我们推荐将store中的state赋值给需要使用该状态的组件的计算属性中(一定不能把state赋值给data,state发生改变时不会重新给data赋值)
3.
Vuex为了简化 state与计算属性配合使用时的代码,提供了一个辅助函数mapState可以简化上面的写法
1
2
3
4
5
6
7
8
9
10
11
12
13
14 // 首先引入辅助函数mapState
import {mapState} from 'vuex'
/*
computed: {
book() {
return this.$store.state.book;
},
}*/
// 下面的写法等价于上面的写法
computed: {
...mapState(['book'])
}
Getters
getter就是Vuex的计算属性,开发人员可以将state 或其他getter 计算后的的返回值存放在指定getter中,当前getter会将这些依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。可以认为是 store 的计算属性
1 | state: { |
在任何组件中都可以通过this.$store.getter.属性名访问
getter在组件中依然存放在组建的计算属性中
1
2
3
4
5computed: {
score() {
return this.$store.getters.calcScore;
}
}
Vuex为 getters 同样提供了辅助函数mapGetters1
2
3
4
5
6
7
8
9
10方法一: mapState可以接收一个字符串数组作为参数,数组中的每一项字符串都会成为当前组件的计算属性并且与Vuex中的同名getter建立映射对应关系。
computed: {
...mapGetters(["calcScore"])
}
方法二: mapGetters可以接收对象作为参数,对象的每一个key都会成为当前组件的计算属性名,value必须是一个字符串并且与Vuex中的同名getter建立映射对应关系。
computed: {
...mapGetters({
s1: 'calcScore'
})
}
Mutations
vuex规定mutation是唯一可以修改state的地方
1 | mutations: { // 修改state的方法 |
在组件中必须使用$store.commit方法提交指定mutation,指定mutation才会触发
1 | methods: { |
注意: Mutation 需遵守 Vue 的响应规则 Vuex 的 store 中的状态是响应式的,那么当我们变更状态时,监视状态的 Vue 组件也会自动更新。这也意味着 Vuex 中的 mutation 也需要与使用 Vue 一样遵守一些注意事项:
1、最好提前在你的 store 中初始化好所有所需state属性。
2、当需要在对象上添加新属性时,你应该使用 Vue.set(obj, ‘newProp’, 123), 或者以新对象替换老对象
1 | mutations: { |
注意1: Mutation 内部只允许同步操作,原因在vuex中mutation是唯一可以修改state的地方,所以开发中我们有时会对mutation进行数据追踪观察state是否按照预期发生改变,这样做的化就可以在开发中捕获大量的错误,如果mutation允许异步操作的话,就会导致我们的数据追踪变得混乱不可查阅。
2:因为每次提交mutation都是传入commit函数一个同名mutation字符串,这样的操作有时会导致提交字符串与mutation名不一致导致指定mutation没有被提交,这个问题尤其会出现在多人开发中。为了避免该问题vuex推荐专门创建一个名为 mutation-types.js 文件存储当前应用中所有的mutation名,开发人员就可以使用变量的方式声明提交指定的mutation了
1 | export const ADD_CURRENT_COUNT = 'ADD_CURRENT_COUNT' |
1 | // store中的mutation全部使用 mutation-types声明好的常量作为函数名 |
1 | // 组件调用这些mutation时 直接通过引入对应的mutation-types常量 |
Vuex为 mutations 同样提供了辅助函数 mapMutations
方法一: mapMutations可以接收一个字符串数组作为参数,数组中的每一项字符串都会成为当前组件的方法并且与Vuex中的同名mutation建立映射对应关系。
1 | import {mapMutations} from 'vuex' |
方法二:mapMutations可以接收对象作为参数,对象的每一个key都会成为当前组件的方法名,value必须是mutation的同名字符串与Vuex中的mutation建立映射对应关系。
1 | computed: { |
Actions
Vuex给开发人员提供了一个可以执行异步操作的函数action
Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象
注意: action函数中接收两个参数
参数一 context 与 store对象相似所以可以访问 context.state / context.getters / context.commit / context.dispatch
参数二 action的载荷,action载荷与mutation一样只有一个如果需要传递多个参数请传递对象
★★★ action是不允许直接修改state的
1 | state: { |
在组件中分发 Action
直接使用this.$store.dispatch
1 | created() { |
Vuex为 action 同样提供了辅助函数 mapActions,mapActions生成的方法只接受一个参数,这个参数就是当前action的载荷
1 | created() { |
Actions 支持同样的载荷方式和对象方式进行分发:
1 | // 以载荷形式分发 |
Modules
由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。
为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割:
1 | state: { |
虽然在我们在实例化vuex.Store时创建了不同的模块,但是最终生成的store对象所有数据(包含子模块的数据)依然存储在同一个state getters mutations actions中。
对于模块内部的 mutation 和 getter,接收的第一个参数是模块的局部状态对象。
同样,对于模块内部的 action,局部状态通过 context.state 暴露出来,根节点状态则为 context.rootState:
1 | const moduleA = { |
对于模块内部的 getter,根节点状态会作为第三个参数暴露出来:
1 | const moduleA = { |
命名空间
默认情况下,模块内部的 action、mutation 和 getter 是注册在全局命名空间的——这样使得多个模块能够对同一 mutation 或 action 作出响应。
如果希望你的模块具有更高的封装度和复用性,你可以通过添加 namespaced: true 的方式使其成为带命名空间的模块。当模块被注册后,它的所有 getter、action 及 mutation 都会自动根据模块注册的路径调整命名。例如:
1 | const store = new Vuex.Store({ |
启用了命名空间的 getter 和 action 会收到局部化的 getter,dispatch 和 commit。
在使用模块内容时不需要在同一模块内额外添加空间名前缀。更改 namespaced 属性后不需要修改模块内的代码。
module state
存放在module中的state,是否开启命名空间使用方式都是一样的。都是通过store.state.模块名.state属性名
辅助函数mapState获取指定模块的属性,必须使用 "属性名:函数的形式"
1 | ...mapState({ |
当使用 mapState, mapGetters, mapActions 和 mapMutations 这些函数来绑定带命名空间的模块时,写起来可能比较繁琐:
1 | computed: { |
对于这种情况,你可以将模块的空间名称字符串作为第一个参数传递给上述函数,这样所有绑定都会自动将该模块作为上下文。于是上面的例子可以简化为:
1 | computed: { |
而且,你可以通过使用 createNamespacedHelpers 创建基于某个命名空间辅助函数。它返回一个对象,对象里有新的绑定在给定命名空间值上的组件绑定辅助函数:
1 | import { createNamespacedHelpers } from 'vuex' |
module getters
所有module中的getter是直接存储在store.getters中的,依然通过store.getters.属性名访问
当开启了命名空间后module,getters 获取方式发生改变
变为 –>store.getters['模块名/getter属性名']
所以开启命名空间的getter可以与其他模块根store中的getter同名
1 | store.getters.reverseName 根store的getter |
辅助函数mapGetter 获取module的getter方法没有变化的
1 | 模块中getters函数包含四个参数 |
1 | computed: { |
module mutation 和 action
所有mutation和action也是直接存储在store中的,依然通过store.dispatch('mutation名') store.dispatch('action名')触发的
在开发中如果你的模块如果没有开启命名空间,mutation与action 在模块与模块之间 或模块与根store之间存在同名mutation / action 是不会造成命名冲突不会报错的,但是如果commit / dispatch 这些同名 mutation / action时他们将都会执行。
当开启了命名空间后module,mutation与action方法名会发生改变
变为 –> '模块名/mutation名' '模块名/action名'
1 | // $store.commit('myMutation') => '根mutation的 myMutation方法被触发了' |
模块中mutation\action函数无论是否开启具名空间依然只包含两个参数
参数一: 当前模块的局部state
参数二: 载荷
命名空间开启的模块action内部 context.commit 提交mutation时dispatch分发action时会自动添加命名空间前缀,从而实现只提交当前模块mutation/action的效果
1 | 如果你想要在开启命名空间模块的`action`中使用`context提交/分发全局mutation/action`请在`commit dispatch`方法传入`第三个参数{root:true}`代表调用全局 |
store.commit和store.dispatch的区别及用法
mutations 和 actions 都要在组件的methods中使用 ,而state和getters都是在组件中的computed中使用
dispatch是在actions中使用的,action是不允许直接修改state的,所以我们要在actions中定义提交mutations的方法
1、commit: 用来提交当前模块的mutations
dispatch: 用来提交当前模块的actions(actions可以提交mutations,可以进行异步操作)
commit 有些做不到的可以用 dispatch 进行提交
2、mutations修改state, action提交mutations。但是如果修改完还想做其他事情就用actions比较方便(then后执行想要做的事情) ==> this.$store.dispatch().then()
3、commit: 同步操作 存储 this.$store.commit(‘changeValue’,name)
dispatch: 异步操作 存储 this.$store.dispatch(‘getlists’,name)
---