1.简介html
vuex是 vue官方推荐的一个状态管理器。当咱们遇到不少状态改变时,组件之间的通讯就会变得复杂,这时候vuex的强大就展示出来。vue
咱们从vuex的原理以及vuex的api两个部分介绍vuexes6
原理:vuex
vuex的核心是store对象,它承载了vue的状态管理。vuex的实现分为了2个部分,第一个部分是store的建立,以及第二部分store的挂载,而且解析store。api
vuex经过插件安装的形式来使得vue挂载vuex的store,固然这个是在vue组件的createBefore阶段实现的。随后Vuex将它直接挂载到 $options.$store 以供使用vue使用。数组
对于vuex的属性,Vuex 会将 vuex 属性解构成 getters 和 actions。并将 getters 的每一个属性都挂载 vm 下(有可能被组件的 $options.data() 的属性覆盖),同时定义每一个值的 getter 方法,但并不会定义 setter 方法,这是由于根据 Vuex 的设计是不容许开发者直接在组件内更改 store.state,而对数据的改动要经过提交 mutation。Vuex 实际上将 vm.vuex.getter 内的属性看成当前 vm 的计算属性来处理。和计算属性的区别是计算属性依赖计算的是 vm.$options.data 内的值,而 vm.vuex.getter 的属性依赖计算的是 store._vm.$options.data。这样全部组件的渲染都将均可以直接从状态树拿数据来渲染 UI 。promise
全部的组件均可以和vuex的状态树进行数据交互。可是不容许直接改变状态树的状态,应该用vuex的mutations来提交状态的改变。vuex会将actions内的方法绑定到vue的$options.methods下,它们与vue中定义的方法并无区别。而 actions 内的方法将经过 dispatch 触发 mutations 来更新全局状态,actions方法与mutations的区别是,mutations改变state而且必须是同步改变,而actions能够做为异步提交的方法,dispatch 能够接收一个promise,而且返回一个promise。异步
2.API:函数
state:在vue中引入store对象,在子组件中经过this.$store来访问vuex中状态,而且咱们最好在vue的computed中获取vuex的状态。this
mapState:这是一个语法糖,能够快捷的获取更多的state。
接受一个object参数:
// 在单独构建的版本中辅助函数为 Vuex.mapState import { mapState } from 'vuex' export default { // ... computed: mapState({ // 箭头函数可以使代码更简练 count: state => state.count, // 传字符串参数 'count' 等同于 `state => state.count` countAlias: 'count', // 为了可以使用 `this` 获取局部状态,必须使用常规函数 countPlusLocalState (state) { return state.count + this.localCount } }) }
当计算属性的名称和节点名称相同时,也能够接受一个数组对象。
computed: mapState([ // 映射 this.count 为 store.state.count 'count' ])
对象展开:合成最终的computed属性
computed: { localComputed () { /* ... */ }, // 使用对象展开运算符将此对象混入到外部对象中 ...mapState({ // ... }) }
getter:store的计算属性,在获取数据的时候,咱们能够经过getter进行数据的操做,在相同地方用到的数据操做就不须要写一个公用的处理函数。它接受2个参数,state和getters。
getters: { // ... doneTodosCount: (state, getters) => { return getters.doneTodos.length } } store.getters.doneTodosCount // -> 1
mapGetters:
export default { // ... computed: { // 使用对象展开运算符将 getters 混入 computed 对象中 ...mapGetters([ 'doneTodosCount', 'anotherGetter', // ... ]) } }
或者
mapGetters({ // 映射 this.doneCount 为 store.getters.doneTodosCount doneCount: 'doneTodosCount' })
mutations:vuex提交状态的惟一方式。mutations更像一个事件监听器,当vue中commit了信息以后,相应的mutation才会执行相应的回掉函数。它接受2个参数,state和object。
由于vue是响应式的,因此mutations也应该遵照vue的动态绑定,因此在须要使用mutations前,尽可能初始化。或者是添加时使用vue.set(obj,'new obj', 'value')或者以新运算符state.obj = { ...state.obj, newProp: 123 }
mutations必须是同步函数
组件中提交mutations:
import { mapMutations } from 'vuex' export default { // ... methods: { ...mapMutations([ 'increment' // 映射 this.increment() 为 this.$store.commit('increment') ]), ...mapMutations({ add: 'increment' // 映射 this.add() 为 this.$store.commit('increment') }) } }
actions: actions提交的是mutations,由于mutations是必须为同步状态,actions就提供了一种异步的形式提交mutations,咱们能够在active中去作异步处理,而且提交mutation。它接受一个context参数,这个参数具备store对象相同属性和方法,可是并非store自己。
actions: { increment (context) { context.commit('increment') } }
//或者 使用解值
actions: {
increment ({ commit }) {
commit('increment')
}
}
actions以dispatch来分发
// 以载荷形式分发 store.dispatch('incrementAsync', { amount: 10 }) // 以对象形式分发 store.dispatch({ type: 'incrementAsync', amount: 10 })
组合的actions:
store.dispatch
能够处理被触发的action的回调函数返回的Promise,而且store.dispatch仍旧返回Promise
actions: { actionA ({ commit }) { return new Promise((resolve, reject) => { setTimeout(() => { commit('someMutation') resolve() }, 1000) }) } }
// 能够这样触发
//一个 在不一样模块中能够触发多个 action 函数。在这种状况下,只有当全部触发函数完成后,返回的 Promise 才会执行。
store.dispatch('actionA').then(() => {
// ... store.dispatch
})
// 也能够这样子触发
actions: {
// ...
actionB ({ dispatch, commit }) {
return dispatch('actionA').then(() => {
commit('someOtherMutation')
})
}
}
modules:
Vuex 容许咱们将 store 分割到模块(module)。每一个模块拥有本身的 state、mutation、action、getters、甚至是嵌套子模块——从上至下进行相似的分割。
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 的状态
模块的局部状态
对于模块内部的 mutation 和 getter,接收的第一个参数是模块的局部状态。
const moduleA = { state: { count: 0 }, mutations: { increment (state) { // state 模块的局部状态 state.count++ } }, getters: { doubleCount (state) { return state.count * 2 } } }
对于模块内部的 action,context.state
是局部状态,根节点的状态是 context.rootState。
const moduleA = { // ... actions: { incrementIfOddOnRootSum ({ state, commit, rootState }) { if ((state.count + rootState.count) % 2 === 1) { commit('increment') } } } }
对于模块内部的 getter,根节点状态会做为第三个参数。
const moduleA = { // ... getters: { sumWithRootCount (state, getters, rootState) { return state.count + rootState.count } } }
命名空间:
模块内部的 action、mutation、和 getter 如今仍然注册在全局命名空间——这样保证了多个模块可以响应同一 mutation 或 action。你能够经过添加前缀或后缀的方式隔离各模块,以免名称冲突。你也可能但愿写出一个可复用的模块,其使用环境不可控。例如,咱们想建立一个 todos
模块:
// types.js // 定义 getter、action、和 mutation 的名称为常量,以模块名 `todos` 为前缀 export const DONE_COUNT = 'todos/DONE_COUNT' export const FETCH_ALL = 'todos/FETCH_ALL' export const TOGGLE_DONE = 'todos/TOGGLE_DONE' // modules/todos.js import * as types from '../types' // 使用添加了前缀的名称定义 getter、action 和 mutation const todosModule = { state: { todos: [] }, getters: { [types.DONE_COUNT] (state) { // ... } }, actions: { [types.FETCH_ALL] (context, payload) { // ... } }, mutations: { [types.TOGGLE_DONE] (state, payload) { // ... } } }
咱们也能够运用es6的新方法,symbol作命名;
须要了解更多关于symbol的信息,请移步阮一峰老师的ES6
参考文献: