简介
Vuex 是 专为 Vue 开发的状态管理模式。通常用于跨页面共享数据。
状态管理模式:它采用集中式的存储,管理应用的所有组件状态,并且用响应的规则保证状态以可预测的方式发生变化。利用全局单例模式统一管理组件状态。
Vuex 的流程 action -> mutation -> state -> change
状态管理模式主要包含以下几部分:
- state,驱动应用的数据源;
- view,以声明方式将 state 映射到视图;
- actions,响应在 view 上的用户输入导致的状态变化。
在 Vue2.0 后 Vuex 是主要的跨页面状态管理模式。在大型的单页应用中应该使用Vuex 统一管理状态机。如果是小型的项目,也可以采用 global event bus 进行简单的状态机管理。
核心概念
store 可以理解为一个大的仓库容器,里面存放着应用包含的大部分的状态 state。 它的特点是: 1 状态存储是响应式的 2 不能直接改变 store 中的状态,需要显示的提交mutation。
以下是定义在 store 中包含的参数:
state
页面状态管理容器对象。集中存储components中data对象的零散数据,全局唯一,用来进行统一的状态管理。页面显示所需的数据从该对象中进行读取,利用Vue的细粒度数据响应机制来进行高效的状态更新。
它是单一状态树,用一个对象包含全部的应用层级状态。单一的状态树的好处,可以让我们直接的定位任意的特定状态片段,快速的取得整个应用状态的快照
this.$store.state.count; // 获取状态树中的 全局 count 属性
store.state.count;// 获取单个状态属性
在Vue-cli 中 通过在 new Vue 中注册 store 来挂载全局状态机。处理 state 还有一些辅助方法
-
mapState 在一个组件中获取多个状态的时候,通过mapState({}) 辅助方法可以帮助我们拼装好状态统一处理
-
...mapState({}) 对象扩展运算符 可以返回 多个状态的合集
Getter
state对象读取方法,组件通过该方法读取全局state对象,getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。
const store = new Vuex.Store({
state: {
todos: [
{ id: 1, text: '...', done: true },
{ id: 2, text: '...', done: false }
]
},
getters: {
doneTodos: state => {
return state.todos.filter(todo => todo.done)
}
}
})
store.getters.doneTodos // -> [{ id: 1, text: '...', done: true }]
以上是 Getter 的常规方法,下面的这个是辅助方法:
1 ...mapGetters ({}) 用于映射到局部计算属性
Mutation
**核心点:在 Vuex 中 mutation 都是同步事务 **
在 Vuex 的设计体系中,可以看出修改 store 状态的唯一的方法是提交 mutation 对象。它类似于事件操作,每个mutation 对象 都包含 事件类型 和 回调方法 ,利用 回调方法 修改 store 的状态。
注意事项:
- 当需要在对象上添加新属性时 或 以新对象替换老对象时,需要使用以下方式:
Vue.set(obj, 'newProp', 123)
state.obj = { ...state.obj, newProp: 123 }
- mutation 必须是同步函数
// 定义 mutation
const store = new Vuex.Store({
state: {
count: 1
},
mutations: {
increment (state) {
// 变更状态
state.count++
}
}
})
// 触发 mutation
store.commit('increment')
this.$store.commit('increment')
-
...mapMutations({add: 'increment'}) 将
this.add()
映射为this.$store.commit('increment')
2....mapMutations([ 'increment']) 将 this.increment()
映射为 this.$store.commit('increment')
Action
核心点:在 Vuex 中 Action 都是异步事务
Action 提交的是 mutation,而不是直接变更状态。
Action 可以包含任意异步操作。
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment (state) {
state.count++
}
},
actions: {
// ES5 参数析构
increment ({ commit }) {
commit('increment')
}
}
})
Action 分发
Action 通过 store.dispatch 方法触发, 因为它是异步的,可以在内部进行一些异步操作,分发多重 mutation,对于程序的灵活性有很大的提升。
分发的方法:
// 以载荷形式分发
store.dispatch('incrementAsync', {
amount: 10
})
// 以对象形式分发
store.dispatch({
type: 'incrementAsync',
amount: 10
})
// 在组件中分发
this.$store.dispatch('xxx')
// 利用 mapActions 分发
...mapActions({
add: 'increment'
})
// 异步多重分发
store.dispatch('actionA').then(() => {
})
Module
用于 store 对象 分割成小的模块,每个模块拥有自己的 state、mutation、action、getter。
const moduleA = {
state: { ... },
mutations: { ... },
actions: { ... },
getters: { ... }
}
const moduleB = {
state: { ... },
mutations: { ... },
actions: { ... }
}
const store = new Vuex.Store({
modules: {
a: moduleA,
b: moduleB
}
})
store.state.a // -> moduleA 的状态
store.state.b // -> moduleB 的状态
问答
Q:使用Vuex只需执行 Vue.use(Vuex),并在Vue的配置中传入一个store对象的示例,store是如何实现注入的?
A:Vue.use(Vuex) 方法执行的是install方法,它实现了Vue实例对象的init方法封装和注入,使传入的store对象被设置到Vue上下文环境的store中。因此在Vue Component任意地方都能够通过this.store访问到该store。
Q:state内部支持模块配置和模块嵌套,如何实现的?
A:在store构造方法中有 makeLocalContext 方法,所有module都会有一个local context,根据配置时的path进行匹配。所以执行如dispatch('submitOrder', payload)这类action时,默认的拿到都是module的local state,如果要访问最外层或者是其他module的state,只能从rootState按照path路径逐步进行访问。
Q:在执行dispatch触发action(commit同理)的时候,只需传入(type, payload),action执行函数中第一个参数store从哪里获取的?
A:store初始化时,所有配置的action和mutation以及getters均被封装过。在执行如dispatch('submitOrder', payload)的时候,actions中type为submitOrder的所有处理方法都是被封装后的,其第一个参数为当前的store对象,所以能够获取到 { dispatch, commit, state, rootState } 等数据。
Q:调试时的"时空穿梭"功能是如何实现的?
A:devtoolPlugin中提供了此功能。因为dev模式下所有的state change都会被记录下来,'时空穿梭' 功能其实就是将当前的state替换为记录中某个时刻的state状态,利用 store.replaceState(targetState) 方法将执行this._vm.state = state 实现。
总结
-
应用层级的状态应该集中到单个 store 对象中。
-
提交 mutation 是更改状态的唯一方法,并且这个过程是同步的。
-
异步逻辑都应该封装到 action 里面。
-
dispatch:操作行为触发方法,是唯一能执行action的方法。
-
commit:状态改变提交操作方法。对mutation进行提交,是唯一能执行mutation的方法。
-
Vue组件,HTML页面上,负责接收用户操作等交互行为,执行dispatch方法触发对应action进行回应。
-
Vue组件接收交互行为,调用dispatch方法触发action相关处理,若页面状态需要改变,则调用commit方法提交mutation修改state,通过getters获取到state新值,重新渲染Vue Components,界面随之更新。
网友评论