Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。
它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
以上是官方套话,详情直接看官网。
1.对状态机vuex的理解
- 是一种状态管理模式,抽取共享状态
- 保证状态是可预测的变化
- 单向数据流
官
方
祖
传
的
单
向
数
据
流
图
。
官方祖传的单向数据流图。
官方祖传的单向数据流图。
2.安装
npm install vuex --save
3.vuex的基础结构
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {},
mutations: {},
actions: {},
getters: {},
modules: {}
})
在main.js中引入并挂载到实例上即可在组件中访问共享的状态:
import store from './store'
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
4.使用方法
挂载之后,在组件内访问方式如下:
- 访问共享状态
this.$store.state.STATE_NAME
- 提交状态变化
this.$store.commit(MUTATIONS_FUNC, PAYLOAD);
// 参数一:mutations中的提交修改state的方法名
// 参数二:载荷参数
- 异步处理并提交修改
this.$store.dispatch(ACTIONS_NAME, PAYLOAD);
// 参数一:actions 中的异步方法名
// 参数二:载荷参数
注:修改state绝对不可直接修改,如果直接修改就违背了***可预测***的特点,可以通过设置 strict: true,此时直接修改state会报错提示。
5.对基础结构的解释
-
state
管理所有共享的状态,同时状态存储是响应式的,所以在computed中返回state
-
actions 异步方法,可返回Promise,也可使用语法糖
actions中可以包含异步操作。
不同于mutations,不可以直接commit。actions中提交的是mutation。
由于actions中的函数提交的是mutations,所以actions的函数接收的参数就是上下store上下文,通过context.commit提交mutation。
actions: { // async await语法糖,不扩展解释 async add({ commit, dispatch, rootMutations }, payload) { commit('gotData', await getData()) } }
-
mutations 只能写同步方法,不可写异步方法!!
唯一可以修改state的地方就是在mutation中进行修改。在mutation中接收state作为参数。在业务组件中通过commit调用指定的mutation,在调用的同时可以传递载荷参数,通常这个参数是对象(为了提交多个参数)。
this.$store.commit(MUTATION_NAME, PAYLOAD); // 等同 this.$store.commit({ type: MUTATION_NAME, params1: VALUE, params2: VALUE }) // 当使用对象形式提交的时候,整个对象都作为PAYLOAD提交到mutations的方法中
vuex的state是响应式,所以mutation的使用也要和vue一样:
- 初始化所需的属性
- 新增删除属性需要使用Vue.set/Vue.delete保证属性的响应
可以将mutations中的事件名称使用常量代替(非必须):使用常量的好处:不易出错,如果出错eslint会提示
// mutation-types.js export const MUTATION_NAME = 'MUTATION_NAME'; // store.js import Vuex from 'vuex' import { MUTATION_NAME } from './mutation-types' const store = new Vuex.Store({ state: {}, mutations: { [MUTATION_NAME] (state) { // todo // 注意:mutation中必须使用同步,不可使用异步,所有需要用异步处理的部分都需要在actions中 } } })
-
getters
vuex可以在store中派生状态(getters也可以理解为store中的computed,拥有和computed一样的特性,返回值会被缓存)。
// store.js import Vuex from 'vuex' import { MUTATION_NAME } from './mutation-types' const store = new Vuex.Store({ state: {}, getters: { GETTERS_NAME: state => { // todo } } })
<!-- 组件内调用 --> <!-- 也可以根据实际情况传参 --> this.$store.getters.GETTERS_NAME
-
modules
为模块化服务,每个模块被模块化后通过modules引入。每个模块都有属于自己的以上的每一部分,包括modules。
import Vue from 'vue' import Vuex from 'vuex' // 引入子模块的vuex import counter from "./counter"; Vue.use(Vuex) export default new Vuex.Store({ // 模块化 modules: { counter }, // 使用严格模式 strict: true })
// module export default { // 设置独立的命名空间,避免命名冲突!!!!!! namespaced: true, state: { counter: 0 }, mutations: { // payload是传递进来的参数 // 此处的state是module内部的state!!!! add(state, payload) { state.counter++; state.counter += payload; } }, actions: { // 第一个参数是vuex上下文,state是通过上下文暴露出来的 // payload是传递进来的参数{} // 此处时通过解构的形式 add({ state, commit, dispatch, rootState }, payload) { return new Promise((resolve, reject) => { setTimeout(() => { commit('add', payload) }, 1000); }); }, // 在module的action中提交或者分发全局store中的mutation或action,那么就需要将{root: true},作为第三个参数传递给commit或dispatch!!!!!!!!!!!!!! someAction ({ dispatch, commit, getters, rootGetters }) { getters.someGetter // -> 'foo/someGetter'/局部 rootGetters.someGetter // -> 'someGetter'/全局 dispatch('someOtherAction') // -> 'foo/someOtherAction'/局部 dispatch('someOtherAction', null, { root: true }) // -> 'someOtherAction'/全局 commit('someMutation') // -> 'foo/someMutation' commit('someMutation', null, { root: true }) // -> 'someMutation' }, }, getters: { // 此处的state是module内部的state!!!! // 直接讲rootState作为参数传递进来(如果有需要) doubleCounter(state, rootState) { // todo } } }
6.模块化以后的vuex如何使用
由于模块化开启了独立的命名空间,这就导致了访问指定的store需要加上命名空间。这就造成了不必要的麻烦。所以要使用vuex提供的辅助函数简化写法:
import { mapState, mapMutations, mapActions, mapGetters } from "vuex";
对于state:
@Component({
components: {
children1
},
computed: {
// 通过扩展运算将需要的state,塞到computed中作为计算属性。
// 数组内名称要和state中的状态名保持一致
...mapState(['PARAMS1','PARAMS2','PARAMS3']),
params() {
// 不影响自定义的计算属性
}
},
})
getters可以看作是store中的计算属性,进一步处理state,返回需要的值。对于getters:
@Component({
components: {
children1
},
computed: {
// 数组内的名称要和store的getters中的名称保持一致
...mapGetters(['GETTERS_NAME1','GETTERS_NAME2']),
params() {
// 不影响自定义的计算属性
}
},
})
mutations中的方法相当于methods中的方法:
methods:{
// 在需要的地方直接调用数组内的名称
...mapMutations(['MUTATIONS_NAME1', 'MUTATIONS_NAME2'])
}
// 等同于
methods:{
MUTATIONS_NAME1(payLoad){
this.$store.commit('MUTATIONS_NAME1',payLoad)
},
MUTATIONS_NAME2(payLoad){
this.$store.commit('MUTATIONS_NAME2',payLoad)
}
}
actions中的方法类似mutation,区别在于 不可直接操作state 通过commit调用mutation去执行修改state。且为异步操作。
methods:{
// 直接通过name去调用action,在action中执行commit动作,从而修改state
...mapActions(['ACTIONS_NAME1', 'ACTIONS_NAME2'])
// 等同于
ACTIONS_NAME1(){
return this.$store.dispatch('ACTIONS_NAME1')
}
}
如有不当之处,请指正。
keep learning