文章目录
什么是状态管理模式?
在了解Vuex之前,我们需要先了解什么是状态管理模式。
在一些大型应用中,有时我们会遇到单页面中包含着大量的组件及复杂的数据结构,而且可能各组件还会互相影响各自的状态,在这种情况下组件树中的事件流会很快变得非常复杂,也使调试变得异常困难。
为了解决这种情况,所以我们引入状态管理这种设计模式,来降低这种情况下事件的复杂程度并且使调试变得可以追踪。
那么什么是状态管理模式呢?
状态管理模式的核心思想就是,将各个组件的共享状态(这里所谓的状态,其实就是组件的一些数据)抽取取出,使用一个全局的单例的对象来进行管理,从而简化程序结构,且易于维护。
用大白话来说就是,将系统中的一些经常需要用到的全局变量,集中起来用一个组件统一管理,其他要使用这些数据的组件,获取或修改这些数据都需要同这个统一管理的组件交互,从而保证这些数据只有一份,当其被修改时,所有组件都可以感知到,结合响应式数据流,可以实时更新所有页面上的数据。
什么是Vuex?Vuex能做什么?
概述
这是Vuex官网的描述:
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式组件。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
看起来有点懵逼~
其实只要理解到上面大白话说的状态管理模式的意思,就能明白他在说什么。说白了Vuex就是上面提到的那个统一管理全局数据的组件,配合Vue的响应式数据流,可以实时变更所有页面上的数据。
原理
下图是Vue官方提供的Vuex原理图:
原理图解析
这个图描述了Vuex工作时的流程,下面举例分步骤详细地解释下:
- 举例A组件需要修改用户信息(用户信息是一个全局数据,即图中的状态),于是A组件去调用修改用户信息的Action,Action实际就是一个函数;
- 修改用户信息的Action被调用,于是去请求后台服务,发起修改用户信息请求,后台若响应失败,则修改失败,流程停止,若响应成功,则派发调用为用户信息这个状态数据赋值的Mutation;
- Mutation其实就是负责实际修改全局数据的函数,通常也只负责修改下State,不会有其它逻辑;
- 用户信息的State,这个全局数据被Mutation修改了,于是所有使用了用户信息的组件,它们视图上的用户信息数据都会实时更新,至此,就完成了一次状态管理。
为什么要区分Action与Mutation?
看了上面的示意图以及解析,可能会产生一个疑问,为什么我们不直接在Action中修改全局数据呢,而要画蛇添足似的弄个Mutation?
这是关于这个问题,Vue的作者在知乎给出的回答:
中文翻译可能有些偏差(不是我翻的)。区分 actions 和 mutations 并不是为了解决竞态问题,而是为了能用 devtools 追踪状态变化。
事实上在 vuex 里面 actions 只是一个架构性的概念,并不是必须的,说到底只是一个函数,你在里面想干嘛都可以,只要最后触发 mutation 就行。异步竞态怎么处理那是用户自己的事情。vuex 真正限制你的只有 mutation 必须是同步的这一点(在 redux 里面就好像 reducer 必须同步返回下一个状态一样)。
同步的意义在于这样每一个 mutation 执行完成后都可以对应到一个新的状态(和 reducer 一样),这样 devtools 就可以打个 snapshot 存下来,然后就可以随便 time-travel 了。
如果你开着 devtool 调用一个异步的 action,你可以清楚地看到它所调用的 mutation 是何时被记录下来的,并且可以立刻查看它们对应的状态。其实我有个点子一直没时间做,那就是把记录下来的 mutations 做成类似 rx-marble 那样的时间线图,对于理解应用的异步状态变化很有帮助。
作者:尤雨溪
链接:https://www.zhihu.com/question/48759748/answer/112823337
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
总结一下:
- 区分Action和Mutation是为了devtools服务,从原理图中也能看到Mutation是和开发工具交互的,所以这并不是设计模式所需要的,不必过分纠结;
- 异步操作应该放在Action中,Mutation中只应该有同步操作,实际使用中,我们的Mutation通常只有修改State的简单逻辑;
Vuex的核心概念
Store(仓库)
Vuex程序会通过new Vuex.Store初始化一个Store,Vuex所有的操作都是围绕着Store来的,Store就是Vuex的一个根对象。
State(状态)
State就是我们前面提到的组件的状态,其实就是一些全局数据,现在我们把这些数据统一管理在State中,方便所有组件获取使用,并且可以响应式地更新。
Store对象是根对象,所以State数据会存放在Store中。
Mutation(变更)
Mutation函数负责实际修改State中的状态数据,直接操作State中的数据值。
Action(动作)
在Vuex中我们不会直接操作State中的值,这样会容易导致混乱,我们需要通过Action函数来调用对应的Mutation函数,然后由Mutation来实际负责修改State中的数据。
在Action函数中,你也可以通过Ajax从后端或其它的一些渠道来获取需要更新的数据。
Getters
Vuex 2.0中将Getters引入了Store中,如同Java中的get函数,我们可以通过Getters获取一些全局性的数据。
通常是当我们需要对数据进行一些逻辑处理时才使用getter,类似于计算属性computed,只不过getter是针对State的,如果没有这种需求,可以不使用getter。
Modules
Vue 2.0中对State进行了模块化处理,即每个模块都可以有各自的State,最终通过modules聚合在一起,方便管理维护。
Vuex的简单应用实例
示例代码目录结构
src
----support
--------vuex
------------modules
----------------user.js
------------getters.js
------------index.js
user.js
user模块的状态管理代码,可以存在多个这种模块
const user = {
// 这就是我需要全局共享的数据
state: {
name: '',
age: '',
school: ''
},
// Mutation中仅有简单的赋值逻辑
mutations: {
SET_USER: (state, user) => {
state.name = user.name
state.age = user.age
state.school = user.school
},
},
// 我们在Action中修改用户数据,修改成功后,更新全局数据
actions: {
changeUser({
// 这里可以拿到commit与state,commit用来分发到mutation,state即上面的state对象,可以拿到里面的数据,但不建议在这里进行修改
commit,
state
}, user) {
// 请求后台服务修改用户数据
axios.post('/user/changeUser', user)
.then(r => {
if (r.data.code == 0) {
// 修改用户成功,使用commit分发操作到mutation
commit('SET_NAME', user)
}
})
}
}
}
export default user
业务代码调用Action
this.$store.dispatch('changeUser', user)
// 若需要在Action执行成功或失败后执行回调,可这样写
this.$store.dispatch('changeUser', user)
.then(res => {
alert('change success')
})
.catch(res => {
alert('change fail')
})
index.js
index.js的作用是初始化Vuex,并聚合所有的模块将其挂载到Vuex的Store中,供全局调用
import Vue from 'vue'
import Vuex from 'vuex'
import user from './modules/user'
import getters from './getters'
// 引入Vuex
Vue.use(Vuex)
// 初始化Store
const store = new Vuex.Store({
// 聚合所有的模块,这里仅有user
modules: {
user
},
getters// Getters也需要在这里挂载到Store中
})
export default store
当然还需要在main.js中引入上面的index.js,并挂载到Vue对象上,供全局调用
//./store/index和./store都可以,如果省略index vue会自动寻找index
import store from './store'
Vue.prototype.$store = store
getters.js
const getters = {
getUser: state => {
// 我们可以在这里将user组合成对象,方便使用
return {
name: state.user.name,
age: state.user.age,
school: state.user.school,
}
}
}
export default getters
业务代码使用State数据
以下两种用法都可以实现数据响应式实时更新
<!--从getter中获取-->
<div>{{$store.getters.getUser.name}}</div>
<!--直接从state中获取-->
<div>{{$store.state.user.name}}</div>
要不要用Vuex?
对于Vuex我们基本有了一个比较清晰的认知,那么在什么时候我们的程序应该使用Vuex呢?
官网为我们给出了答案:
Vuex 可以帮助我们管理共享状态,并附带了更多的概念和框架。这需要对短期和长期效益进行权衡。
如果您不打算开发大型单页应用,使用 Vuex 可能是繁琐冗余的。确实是如此——如果您的应用够简单,您最好不要使用 Vuex。一个简单的 store 模式就足够您所需了。但是,如果您需要构建一个中大型单页应用,您很可能会考虑如何更好地在组件外部管理状态,Vuex 将会成为自然而然的选择。
参考文章:
https://www.cnblogs.com/Leophen/p/11271713.html
《Vue前端开发快速入门与专业应用》–陈陆杨