Vuex 就是前端为了方便数据的操作而建立的一个” 前端数据库“,用来管理所有组件的数据。
state 就是数据库
getter 用来 获取 数据
mutation 用来定义一些方法对数据进行 修改/存储
actions 呢。你想呀,后端从前端拿到了数据,总要做个异步处理吧,处理完了再存到数据库中(.then( () => {异步处理完成后执行})
)。其实这就是
action的过程。如果是个同步操作,那么可以直接丢到数据库,所以vuex也可以在
action 中直接存,就是直接mutation。
在我看来,Vuex 相当于某种意义上设置了读写权限的全局变量,将数据保存保存到该“全局变量”下,并通过一定的方法去读写数据。
为什么使用Vuex
如图所示,顶层父组件App有一个数据a:123
,组件A想要获取这个数据,必须通过props一层层向下传App -> G -> A
,B组件也想获取数据a,必须通过props一层层向下传App -> E -> D ->B
如果B组件有个按钮,点击后想要修改a的值,则必须通过自定义事件$emit()
一层层向上通知父组件B -> D -> E -> App
如图所示,用了Vuex后,相当于建立了一个前端数据库,所有的组件都可以直接获取到Vuex里的数据,并且可以直接修改数据
使用场景
- 当一个项目的组件的层级有好几层,而且有些组件需要获取同一个数据时(避免数据一层层向下传递)
- 当不同的组件,它们有个事件是需要更改同一个数据时(避免自定义事件一层层向上传)
全局共享的数据使用vuex,比如用户信息,因为用户的权限,头像,昵称等等常常会出现在各个不同的组件中,此外,不需要实时更新的数据,都需要保存起来,减少不必要的http请求
Vuex的数据变化过程
前端通过 action 进行异步处理数据后通过
context.commit
传递给mutation,然后通过 mutation 把数据放入数据库(state)中,哪个组件要用就通过
getter 从数据库(state)中取。更改 Vuex 的 store 中的状态的唯一方法是提交(commit) mutation
- 同步逻辑可以直接写到 mutation 里面,通过
this.$store.commit('xxx')
进行提交 - 异步逻辑都应该封装到 actions 里面,通过
this.$store.dispatch('xxx')
方法调用
导出与注入
|
|
将store.js导入到入口文件,挂载到Vue实例的配置项里
state 数据
|
|
在组件中获取state
|
|
通过this.$store.state.xxx
就可以获取state里的数据了
利用辅助函数mapState获取数据
语法:...mapState(['数据名1','数据名2'])
也可以直接在html中通过$store.state
获取【不推荐这种写法】
mutation 变更
mutation对state里的数据进行 修改/保存
mutation里的方法,第一个参数始终是state,后面可以传入额外的参数
文档:mutations
在组件中提交mutation(变更)请求
如果mutations里的方法是同步操作,那么组件可以直接提交commit请求
|
|
你也可以直接在html中通过$store.commit
提交变更请求
如果mutations里的方法需要异步执行,怎么办(比如setTimeout,1秒之后才执行state.count++)?通过actions!
actions 调用
文档:action
在actions中,通过context.commit()
来调用mutations里的方法
实践中,我们会经常用到 ES2015 的 参数解构 来简化代码(特别是我们需要调用 commit 很多次的时候):
在组件中提交action(调用)请求
在组件中,通过dispatch调用action,然后store.state.xxx获取数据
文档:组件通过dispatch调用vuex里的actions
组件通过this.$store.dispatch()
调用store实例里面 actions里定义的方法,然后在计算属性computed里通过return this.$store.state
获得state里的数据
mapActions
mapActions
映射为 this.$store.dispatch
mapState
mapState
映射为 this.$store.state.xxx
当一个组件需要获取多个状态时候,将这些状态都声明为计算属性会有些重复和冗余。此时可以用使用 mapState 辅助函数,然后将数据放入组件的计算属性内
如果映射的计算属性的名称与 state 里的名称相同时,我们也可以给 mapState 传一个字符串数组。
如果该组件有自己的计算属性,怎么办?混入计算属性
像上面这种key和value相同的情况,可以将对象写成数组的形式
Getter
getter类似Vue中的计算属性
有时候我们需要从 store 中的 state 中派生出一些状态,例如需要将state中的firstName和lastName合并,这时需要定义一个计算属性fullName
如果有多个组件需要用到此属性,我们就得每次都手写一遍这个计算属性的代码,Vuex 允许我们在 store 中定义“getter”(可以认为是 store 的计算属性)。
然后,所有的组件都可以通过this.$store.getters.fullName
获取这个属性文档:Getter
等同于
!注意,store.js自身无法获取getters里面的数据;在Vue中,可以直接获取计算属性,但是在Vuex中,无法获取getters里的数据
其实,从mutation的第一个参数可以看出,它是通过第一个参数 state 来间接修改state里的数据;而mutation内部并没有提供getters这个参数
mapGetters
文档:mapGettersmapGetters
映射为 this.$store.getters.xxx
关于辅助函数
|
|
辅助函数传递payload
载荷要在html中传递过去,而不是在methods里!!!!
|
|
|
|
参考地址:https://segmentfault.com/q/1010000011006052
另一种方式传递payload
单独在methods里定义一个方法来调用
|
|
参考地址:https://segmentfault.com/q/1010000009563211
module
如果将所有页面的数据全部放在一个store里,会显得十分臃肿。为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、getter、mutation、action
|
|
从而实现,每个模块单独维护各自的数据状态
模块的局部状态
对于模块内部的 mutation 和 getter,接收的第一个参数是模块的局部状态state。
对于模块内部的 action,局部状态通过 context.state 暴露出来,根节点状态则为 context.rootState:
在组件中获取模块中的数据
|
|
导入封装的$request
|
|
然后就能在vuex中直接使用this.$request()
了