一. 什么是Vuex
官方解释上说Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式,它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
我们可以理解为vuex就是一个大仓库,存放我们的变量。
二.什么场景下使用Vuex
在实际开发过程中,我总结了一下,有两种场景会使用到它。
1.有些变量很多组件都要用到,比如我们用户登录信息及一些别的全局性很多页面很多组件都需要用到的信息;
2.业务层比较复杂,存在多级父子组件关系,要进行多级数据传递时。如下图所示,当要从great-grandfather向brother1或者brother2传递信息,或是要反向传递时,就会比较繁琐,此时用vuex就会很方便。
其实就是,多个组件需要共享的状态都可以放在vuex中。
三.vuex的几个核心概念
1.state
1.1 简介
这个地方就是存放状态(变量)的地方,vuex使用单一状态树,每个应用将仅仅包含一个 store 实例,使它可以作为唯一数据源的存在,方便管理和维护。
1.2 使用
1)安装vuex
import vuex from "vuex"
import Vue from "vue"
Vue.use(vuex);
2)Vuex 通过 store 选项,提供了一种机制将状态从根组件“注入”到每一个子组件中(需调用 Vue.use(Vuex)):
new Vue({
router,
store,
render: (h: any) => h(App),
}).$mount('#app')
通过在根实例中注册 store 选项,该 store 实例会注入到根组件下的所有子组件中,且子组件能通过 this.$store 访问到。
ps:调用Vue.use方法的时候,实际上,会调用vuex.install方法,他会在Vue的原型对象prototype上绑定一个$store
属性。会将这个创建的store实例赋值给这个属性,那他是怎么获取到这个store实例的呢?因为在Vue实例中我们挂载了这个store实例,他就是通过options.store获取到这个store实例的:Vue.prototype.$store=根实例.options.store
。所有的组件都继承Vue的原型,所以都会有$store
属性
1.3 mapState
有时候需要获取多个状态,但是使用计算属性会调用多次,显得麻烦,这里借助mapState方法来获取state。
使用mapState需要引入该方法。
import { mapState } from 'vuex';
使用时写在computed中:
computed: {
...mapState('storeName', ['state1', 'state2']),
},
2.getter
2.1 简介
getter可以认为是 store 的计算属性,只有当它的依赖值发生了改变才会被重新计算(所以兼容一定要写好吖!!!)。有时候我们需要从 store 中的 state 中派生出一些状态,就可以使用getters。也就是说,有的时候我们需要一些数据,可以通过处理state中的值来获得,就可以用getter。
还需要注意的是:getters是一个属性,不是一个函数
2.2 使用
1.在store中:getter其实有2个参数,但第二个参数是可选的,第一个参数是将仓库的state属性传入,第二个参数是将仓库的getters属性传入 例如:
getters: {
// 只传第一个参数
currentPage(state) {
return state.currentPage
},
// 传2个参数
getCurrentPageNum(state, getters) => {
return getters.currentPage
}
}
2.在需要使用该数据的vue文件中,写在computed中:
computed: {
...mapGetter('storeName', ['getState1', 'getState2']),
},
3.mutations
3.1简介
mutation的作用就是修改state的。并且修改state的唯一途径就是提交mutation。
还需注意的一点是:mutations必须是同步函数(devtool这个工具是监听mutations的,如果mutations中存在异步操作它是监听不到状态改变的。当 mutation 触发的时候,回调函数还没有被调用,所以任何在回调函数中进行的状态的改变都是不可追踪的)
3.2使用
1.在store中,接收2个参数,第一个为state,第二个为传递的进来的参数
mutations: {
setCurrentPage(state, payload) {
state.currentPage = payload
},
}
2.在需要使用该方法的vue文件中,写在methods中:
methods: {
...mapMutations('storeName', ['setCurrentPage',]),
}
4.actions
4.1 简介&&使用
action 类似于 mutation,不同在于:
1)action 提交的是 mutation,而不是直接变更状态;
2)action 可以包含任意异步操作。 前面说过mutation必须是同步函数,所以在需要异步处理数据时,就用到了action。
3)在mutation中保持功能单一原则下,如果有一个操作要用到多个mutation,也可用action
这里是一个🌰:
mutation中有多个方法:
mutations: {
functionA(state, payload) {
state.a = payload
},
functionB(state, payload) {
state.b = payload
},
functionC(state) {
state.c = 'test'
},
}
如果这个时候,需要一个方法,满足条件d的时候调用mutation的A方法及B方法;不满足的话调用C方法,那么可以在actions中这么写:
actions: {
uniteFun(context, payload) {
if(d) {
context.commit('functionA', payload)
context.commit('functionB', payload)
} else {
context.commit('functionC')
}
}
}
在需要使用该方法的vue文件中,写在methods中
methods: {
...mapActionss('storeName', ['uniteFun',]),
}
上面有说到,如果需要处理异步数据,也可用action,接下来,又是一个🌰:
actions: {
uniteFun(context, payload) {
context.commit('functionA', payload)
context.commit('functionB', payload)
setTimeout(() => {
context.commit('functionC')
}, 1500)
}
}
5.modules
5.1 简介
官方介绍说:由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割。
其实就是,如果把所有的数据都存到一个大的store中,会很多并且非常大,所以我们可以根据业务实际场景或针对数据不同类型分为很多类,每一类都相当于是一个模块,有store中的全部属性,其中对于模块内部的 mutation 和 getter,接收的第一个参数是模块的局部状态对象。
5.2 注意事项
默认情况下,模块内部的 action、mutation 和 getter 是注册在全局命名空间的,所以如果要使我们的模块有更好的复用性及更高的封装度,最好添加namespaced: true
,使它成为带命名空间的模块。
四.结语
努力学习中,会持续更新并补充,求大佬们指点~~
鞠躬~~~