介绍
Vuex的设计思想
Vuex把所有组件的所有状态和数据放在同一个内存空间去管理,把它成为state,state的数据可以容易地映射到组件上,来渲染组件,当组件的数据需要发生变化的时候,组件可以通过dispatch一个action,actoin可以做一些异步操作(比如从后端请求数据),action会commit一个mutation(组件里面也可以commit一个mutation),mutation是一个唯一可以修改state的途径,其他任何方式去修改state都是非法的。
使用场景和用来解决哪些问题
我们要修改映射在组件上的数据,可以直接在组件内部进行操作;利用Vuex修改数据,要经过action、mutation,修改数据的路径反而会变长。那我们什么时候需要用到Vuex呢?
- 可以解决复杂应用的组件数据共享。如果不打算开发大型单页应用,使用Vuex 可能是繁琐冗余的。如果您的应用够简单,最好不要使用Vuex。一个简单的 global event bus 就足够您所需了。但是,如果构建一个中大型单页应用,Vuex将会成为自然而然的选择。因为它可以解决多个组件之间的状态共享,如果一些组件是兄弟组件甚至时关联度很低的组件,我们要共享他们的数据就比较困难。
- 可以解决路由间的复杂数据传递,当遇到路由跳转,场景需要传递的参数很复杂的时候,用Vuex传递数据就比较好。
基本用法
安装和配置
首先通过npm安装Vuex:npm install --save vuex
在main.js
里,通过Vue.use()使用Vuex:
|
|
state
仓库store包含了应用的数据(状态)和操作过程。Vuex里的数据都是响应式的,任何组件使用同一store的数据时,只要store的数据变化,对应的组件也会立即更新。
数据保存在Vuex选项的state字段内,比如:
|
|
在任何组件中,可以直接通过$store.state.count
来读取:
|
|
直接写在template里显得有点乱,可以用一个计算属性来表示:
|
|
现在组件中的计数0已经可以显示出来了。
mutations
在组件内,来自store的数据只能读取,不能手动改变,改变store中数据的唯一途径就是显示地提交mutations。
mutations是Vuex的第二个选项,用来直接修改state里面的数据:
|
|
在组件中,通过this.$store.commit
方法来执行mutations:
|
|
组件只负责提交一个事件名,Vuex对应的mutations来完成业务逻辑。
mutations还可以接受第二个参数,可以是数字、字符串或对象等类型。
|
|
|
|
提交mutation的另一种方式时直接使用包含type属性的对象:
|
|
|
|
注意:mutation里不要异步操作数据。如果异步操作数据了,组件在commit后,数据不能立即改变,而且不知道什么时候会改变。可以在action里处理异步,后面再讲。
在写mutation的时候,一个state内的属性对应一个mutation,也就是要体现出mutation的原子性,可以提高它的复用性,比如:
|
|
高级用法
getters
有这样的场景:Vuex定义了某个数据list,它是一个数组:
|
|
如果只想得到小于10的数据,可以在组件的计算属性里进行过滤:
|
|
这样写完全没有问题。但如果还有其他的组建也需要过滤后的数据时,就得把computed的代码完全复制一份,而且需要修改过滤的方法时,每个用到的组件都得修改,这明显不是我们期望的结果,如果将computed的方法也提取出来就好了,getters就是来做这件事的:
|
|
|
|
getters也可以以来其他的getter,把getter时作为第二个参数:
|
|
在我看来,getters的作用就像是组件内的计算属性,用mutation单纯的为state内的属性赋值,保持mutation赋值的原始性,用getters作计算属性过滤。
actions
上面说过,mutation里不应该异步操作数据,所以有了action选项。action与mutation很像,不同的是action里面提交的是mutation,并且可以异步操作逻辑。
action在组件内通过$store.dispatch触发,例如:
|
|
|
|
这样看来显得有些多此一举,但是加了异步就不一样了,我们可以用一个Promise在1秒后提交mutation:
|
|
|
|
Vuex使用的时候,涉及到改变数据的,就使用mutations,存在业务逻辑的,就用action。
上面也讲到,当需要异步获取网络数据的时候,一定得写在action中,得到了数据后才能提交mutation,起到改变state属性的效果。
实战中,或许我们会遇到一个问题:有多个网络请求,而且业务中需要我们做的是先请求到所有的数据,才能提交mutation对state中的属性进行“集体”的赋值,比如页面切换的时候,同时渲染出所有的数据模块会带来较好的体验感,另外要求我们的网络异步请求必须是同时发出的。
这里可以用到Promise.all
对那几个异步网络请求进行封装,比如:
|
|
Promise.all
的作用就是当参数(一个promise数组)中所有的promise都resolve,它才resolve。看上面这个例子很明显了。hexo
modules
modules将store分割到不同的模块。当项目足够大时,store里的state、getters、mutations、actions会非常多,都放在main.js里显得不是很友好,使用modules可以把它们写到不同的文件中。每个modules拥有自己的state、getters、mutations、actions,而且可以多层嵌套:
|
|