Vuex是什么
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
上面是copy自官方的解释,在我的理解看来,vuex相当于复杂版的evenBus,管理项目中一些各个地方都需要使用到的数据,各个地方可能触发的事件。
示例
先写一个十分简单的vuex
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| const store = new Vuex.Store({ state: { todos: [ { id: 1, text: 'todo one', done: true }, { id: 2, text: 'todo two', done: false } ] }, getters: { doneTodos: state => { return state.todos.filter(todo => todo.done) } }, mutations: { setTodoDone (state, index) { state.todos[index].done = true } }, actions: { setTodoDoneAfterTime (state, time) { setTimeout(() => { state.todos.map(todo => { todo.done = true }) }, time) } } })
store.commit('setTodoDone', 2) store.dispatch('setTodoDoneAfterTime', 1000)
|
核心概念
State
存储状态数据,每次变化时可以触发vue的computed,并触发更新相关联的DOM
1 2 3 4 5 6 7
| export default { computed: { count () { return this.$store.state.count } } }
|
但是如果每次取值都要通过声明一个计算属性,那未免也太过麻烦了,所以vuex提供了一个简便的方法mapState
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| import { mapState } from 'vuex'
export default { computed: mapState({ count: state => state.count, countAlias: 'count', countPlusLocalState (state) { return state.count + this.localCount } }) }
|
当映射的计算属性的名称与 state 的子节点名称相同时,我们也可以给 mapState
传一个字符串数组
1 2 3 4
| computed: mapState([ 'count' ])
|
Getter
类似于vue中的computed,获取从store中派生出的一些状态,例如对列表进行过滤并计数,并且与computed一样可以缓存状态的变化
同样,在获取getters时也有一个简便的方法mapGetters
1 2 3 4 5 6 7 8 9 10 11 12
| import { mapGetters } from 'vuex'
export default { computed: { ...mapGetters([ 'doneTodosCount', 'anotherGetter', ]) } }
|
如果你想将一个 getter 属性另取一个名字,使用对象形式:
1 2 3 4
| mapGetters({ doneCount: 'doneTodosCount' })
|
Mutation
更改store中状态的唯一方法就是提交mutation,mutation其实就类似与事件的触发
注意点:
- 对象添加新属性时和vue中一样,必须使用set方法才能触发更新,或者使用新对象替换老对象
1
| state.obj = {...state.obj, newProp: 123}
|
1 2
| export const SOME_MUTATION = 'SOME_MUTATION'
|
1 2 3 4 5 6 7 8 9 10 11 12 13
| import Vuex from 'vuex' import { SOME_MUTATION } from './mutation-types'
const store = new Vuex.Store({ state: { ... }, mutations: { [SOME_MUTATION] (state) { } } })
|
- Mutation 必须是同步函数
- 辅助函数
mapMutations
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| import { mapMutations } from 'vuex'
export default { methods: { ...mapMutations([ 'increment',
'incrementBy' ]), ...mapMutations({ add: 'increment' }) } }
|
Actions
Action 类似于 mutation,不同在于:
- Action 提交的是 mutation,而不是直接变更状态。
- Action 可以包含任意异步操作。
mapActions
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| import { mapActions } from 'vuex'
export default { methods: { ...mapActions([ 'increment',
'incrementBy' ]), ...mapActions({ add: 'increment' }) } }
|
Module
对复杂的store对象进行模块的划分
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| const moduleA = { state: { ... }, mutations: { ... }, actions: { ... }, getters: { ... } }
const moduleB = { state: { ... }, mutations: { ... }, actions: { ... } }
const store = new Vuex.Store({ modules: { a: moduleA, b: moduleB } })
store.state.a store.state.b
|
注意点:
- 默认情况下,模块内部的 action、mutation 和 getter 是注册在全局命名空间的——这样使得多个模块能够对同一 mutation 或 action 作出响应。如果希望你的模块具有更高的封装度和复用性,你可以通过添加
namespaced: true
的方式使其成为带命名空间的模块。当模块被注册后,它的所有 getter、action 及 mutation 都会自动根据模块注册的路径调整命名。
1 2 3 4 5 6 7 8 9 10 11 12 13
| computed: { ...mapState('some/nested/module', { a: state => state.a, b: state => state.b }) }, methods: { ...mapActions('some/nested/module', [ 'foo', 'bar' ]) }
|