Vuex五个概念的简单理解。
1.State 保存共享状态信息的地方。
2.Getters 类似我们单个组件中的计算属性computed,只是它定义在Vuex中。
3.Mutations 修改状态的地方。
4.Actions 做异步操作的地方。
5.Modules 用来专门划分模块的地方,针对不同的模块作数据保存。
State 单一状态树
Vuex使用了单一状态树来管理应用层级的全部状态,单一状态树又叫单一数据源(即Single Source of Truth),也就是将所有的数据信息统一放到store对象进行管理,即使有更多的信息需要划分和管理,store对象有且只有一个,因为只有1个store的时候,能够让我们以最直接的方式找到某个状态的片对,方便我们之后的管理、维护和调试。
如果你的状态信息是保存到多个Store对象中的(也就是说创建了多个store对象分散保留信息),那么之后的管理和维护变得十分艰难,所以说只有1个store对象就好。
Getters 的基本使用,类似计算属性。
-
各组件获取store对象中一些state变异后的状态。
意味着,我们在任何一个组件都可以通过如下代码使用getters中定义的属性。
Getters作为参数使用
获取学生年龄>20的人数有几个?
Getters传递参数
-
getters默认是不能传递参数的,如果希望传递参数,那么只能让getters本身返回一个函数。
-
我们在上面传入一个参数22(为下面的年龄作判断age),
-
检索我们stuInfo数组当中age>22的学生。
-
符合要求的只有一个,Jhon的age是28岁。
Mutations状态更新
提交(commit)Mutation是Vuex的store状态中的唯一更新方式。
Mutation主要包括两部分:
(1)字符串的事件类型(type)
(2)一个回调函数(handler),该回调函数的第一个参数就是state-
Mutation的定义方式:
-
通过mutation进行状态更新
拿到我们的store对象,调用我们的commit方法,传入一个事件类型
Mutations传递事件类型的同时携带参数过去
在通过mutation更新数据状态的时候,是可以携带一些的而外的参数的,这些参数被称为mutation的载荷(Payload)
上面演示了携带单个参数传递,倘若我们的参数不止一个的话,这个时候,我们需要通过以对象的形式进行传递,也就是Payload一个对象传递过去,这个时候,再从对象中取出相关的信息。
Mutation提交的两种风格
普通提交方式:通过commit进行提交。
另一种特殊的提交风格:通过一个包含type属性的对象进行提交。
-
当我们点击按钮的时候,可以看到我们在Mutation中接收的参数_count不再是一个简单的变量属性,而是一个对象了,所以这里使用_count来接收不再合适,而应该用payload来统一代替。
所以我们可以直接从payload对象里面取出我们的参数_count进行累加
Mutation响应规则
Vuex的store对象中的state状态是响应式的,当state中的数据发生改变时,Vue组件会自动更新我们的界面视图。
在state中定义的属性都会被加入到Vue响应式系统中,而响应式系统通过观察者模式会动态监听state中每个属性的变化,当state中某个属性发生变化时,响应式系统会通知所有界面中用到该属性的地方(组件),让界面发生刷新,(比如我们这里的state中有3个定义的属性:count,stuInfo,books,如果他们当中有某个属性发生变化,都会自动刷新视图)。
简单的理解就是一种数据的联动,你变我也要跟着变,某个数据发生变化就会产生的一种连锁反应。
效果图(连锁反应)如下:
想要让state中的属性被加入到Vue响应式系统,必须遵守的Vuex响应式规则,规则如下:
- 提前在store对象中进行初始化好我们需要的属性。
如果没有提前在store对象中初始化我们需要的属性,则state中的属性不会被加入到Vue响应式系统。
例子:
点击按钮查看效果:
总结:通过数组的索引值修改数组的元素本身就是不支持的,也不会加入响应式系统中,倘若真的要向state对象中赠添某个新属性时,可以使用.splice()方法或Vue.set()方法,或者用新对象给旧对象重新赋值
Vue.set(传入三个参数)方法使用:Vue.set(第一个参数要改哪个对象?第二个参数传入的是对象或者数组,对象用key键(字符串),数组用number下标,第三个参数,你要传入的值)
对象用key键获取
数组用下标:
Vue.delete()方法可以实现响应式删除。
Mutation类型常量--搬砖转换
-
在mutation中,如果我们定义了很多事件类型(也就是其中的方法名称太多了)就很容易混淆写错)
就像这个样子:
- 当我们的项目在不断增大时,同时Vuex管理的状态也会变得越来越多,那么意味着Mutation中的方法也会越来越多,这也意味着使用者需要花费大量的精力去记住这些方法,甚至在多个文件之间来回切换,查看方法名称,甚至如果不是复制,自己手动敲代码还会写错事件类型。
当我们的事件类型名称是一致时,就可以使用类型常量进行转换了,避免纠错。
Mutation类型常量转换的具体步骤(以事件类型:increment为例子作为展示)
-
在src/store目录下创建一个mutation_type.js文件。
-
在App.vue文件中导入已经定义好的INCREMENT常量。
-
在App.vue函数methods定义中我们就可以这样来提交Mutation了,用定义好的常量INCREMENT替换我们的事件类型'increment'。
- 来到store/index.js文件下我们就可以到mutations中来这样替换事件类型increment了。
首先同样得导入定义好的常量INCREMENT
-
这样写的好处
在Mutation中进行异步操作的弊端
通常情况下,Vuex要求我们在mutations中定义的方法必须是同步的,因为同步的方法可以让devtools捕捉到mutations的快照,但如果是异步操作,这个时候的devtools工具将会变得愚钝了,它并不能很好追踪到mutations中的这个方法操作到底什么时候会被完成。
-
下面我们以异步操作(setTimeout定时器)作为例子测试devtools跟踪mutations方法时的灵敏度。
-
我们打开devtools查看状态记录,在mutation中进行异步操作测试,看下devtools工具到底会不会帮助我们实时更新数据的最新状态。
小结:在mutation中不能有异步操作,只能有同步方法,如有异步操作,必须放到actions里面。
actions 放置异步操作,它的功能和mutations类似。
-
actions有个类似mutation中传入的state参数,actions它也有个自己的参数叫context(上下文),这个参数context可以理解为整个store对象,也可以理解为指向this.store对象。
-
那是不是意味着我们可以直接绕过mutations,执行actions操作呢?
-
答案是可以的,但不推荐这么做,为什么呢?我们可以看下官方的图。
-
我们看到上面的图执行actions操作的时候有个提交commit方法,因为actions中的参数context相当于一个store对象,所以我们可以直接使用context.commit( )方法。
-
小结:我们可以看下官方的思维图,理清思路.
-
拓展:我们的mutations是可以传递参数的,actions是否能传递参数payload呢?答案是可以的。
-
既然组件定义的methods里面可以传递一个参数?那能否传递过去一个箭头函数呢?其实也是可以的。
-
如果组件中的methods能传递一个参数,还可以传递一个箭头函数作为参数,那能否同时传递一个参数和一个箭头函数过去呢?也是可以的,只是这时候的携带参数要写成一个对象的形式。
-
但这种方式不够优雅,因为我们携带的参数和我们携带的回调函数混在一起了,我们要做的就是分离。
Vuex的modules核心概念
- modules是模块的意思,为什么需要在Vuex中使用模块化开发思想呢?
- Vue使用了单一状态数的核心概念,至始至终都只能有且只有一个store对象,那么也就意味着很多状态都要交给Vuex大管家来进行管理。
- 如果我们的应用变得非常复杂的时候,store对象中的代码量就有可能变得相当的庞大和臃肿,不利于后期的维护查看。
- 为了解决这个问题,Vuex允许我们开发者使用模块化的开发思想,将一个非常庞大的store大对象分割成一个个小模块(modules)进行管理,而每一个小模块又可以单独抽离出来组成一个单文件,从而进行组织管理。
- 这种单文件组织的模块化开发使每个独立的模块都拥有了自己的state、mutations、actions、getters。
modules模块是Vuex针对state单一状态树核心,而提出来的一种将代码块抽离成一个个单文件进行管理开发和维护,让开发者具备模块化开发思想,简单点就是是为了避免Vuex代码篇幅过大,避免代码过于臃肿而提出的一种解决方案思路,方便开发者后期的维护。
多个模块划分思路
我们在modules里面定义a、b、c模块都可以拥有和store对象一样的对象属性 。
简单的模块抽离组织思路
如何使用modules属性对象中细分出来的单独模块下的state、mutations、actions?
1.模块中使用state案例
-
如果我们打开devtools查看state的话,会发现一件非常有意思的事情。
-
模块中访问state的实现机制,它不关心你的state到底是定义在模块里面还是定义在store这个大对象里面,反正它最终就是能访问到store对象中的state。
-
state取值
2.模块中使用mutations案例
3.模块中使用getters案例
-
getters作为参数传递,拿到上层的getters使用
-
getters的第三个参数rootState获取store大对象中的state数据
4.模块中使用actions案例 -
注意:模块这里actions访问的是属于模块内部自己的mutations,而不是store大对象里面的mutations,模块中actions区别于state,不会自动添加进store大对象中去.
-
打印模块中的actions里面的context看看有什么?
-
模块actions中传多个参数的另外写法:对象的结构赋值
关于对象的结构赋值上手概念理解:
项目结构拆分:将store大对象中的state、getters、mutations、actions、modules分别抽离成单个文件放置。
按照这种模块化的开发思想,所以我们要好好组织一下,重构我们之前的臃肿代码(将state、getters、mutations、actions、modules都写在一个文件里面是不推荐的)。
操作state
操作mutations(官方不推荐我们在store对象保留mutations,而state是推荐保留的,因此我们要将mutations抽离成单文件)
然后来到index.js进行导入,接着在store对象中使用即可。
getters、actions抽离成单文件,操作同上。
moudules抽离成单文件,因为模块可能有多个,官方推荐我们建一个文件夹放置模块。