什么是Vuex
“store”基本上就是一个容器,它包含着你的应用中大部分的状态 (state)。
但Vuex和单纯的全局变量有两点不同:
- Vuex的状态存储是响应式的,也就是说当store中的状态发生变化是,那么组件也会相应地得到更新。
- 不能直接改变store中的状态。唯一途径就是显式地提交(commit)mutation。
State
在Vue组件中获得Vuex状态
由于Vuex的状态储存是响应式的,从store实例中读取最简单的方式就是计算属性中返回某个状态:
1 2 3 4 5 6 7 8 9 10
| const Counter = { template: `<div>{{ count }}</div>`, compute:{ count(){ return store.state.count } } }
|
使用mapState
辅助函数生成属性
1 2 3 4 5 6 7
| computed: { localComputed () { }, ...mapState({ }) }
|
Getter
可以把Getter认为是store的计算属性,getter的返回值会根据它的依赖被缓存起来,只有当他的依赖发生变化才会重新计算。
通过属性访问
Getter接受state作为第一个参数,接受其他getter作为第二个参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| getters: { doneTodos: state => { return state.todos.filter(todo => todo.done) }, doneTodosCount: (state, getters) => { return getters.doneTodos.length } }
store.getters.doneTodosCount
computed: { doneTodosCount () { return this.$store.getters.doneTodosCount } }
|
注意,getter 在通过属性访问时是作为 Vue 的响应式系统的一部分缓存其中的。
通过方法访问
可以通过让getter返回一个函数,来实现给getter传参。
1 2 3 4 5 6 7 8
| getters: { getTodoById: (state) => (id) => { return state.todos.find(todo => todo.id === id) } }
store.getters.getTodoById(2)
|
注意,getter 在通过方法访问时,每次都会去进行调用,而不会缓存结果。
mapGetter
辅助函数
mapGetters
辅助函数仅仅是将 store 中的 getter 映射到局部计算属性:
1 2 3 4 5 6 7 8 9 10 11 12 13
| import { mapGetters } from 'vuex'
export default { computed: { ...mapGetters([ 'doneTodosCount', 'anotherGetter', ]) } }
|
Mutation
更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的 事件类型(type)和 一个 回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数:
1 2 3 4 5 6 7 8 9 10 11 12 13
| const store = new Vuex.Store({ state: { count: 1 }, mutations: { increment (state) { state.count++ } } })
store.commit('increment')
|
提交载荷(Payload)
即向 store.commit
传入额外的参数,即mutation的载荷。
1 2 3 4 5 6 7 8
| mutations: { increment (state, n) { state.count += n } }
store.commit('increment', 10)
|
载荷为对象:
1 2 3 4 5 6 7 8 9 10
| mutations: { increment (state, payload) { state.count += payload.amount } }
store.commit('increment', { amount: 10 })
|
使用常量代替 Mutation 事件类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| export const SOME_MUTATION = 'SOME_MUTATION'
import Vuex from 'vuex' import { SOME_MUTATION } from './mutation-types'
const store = new Vuex.Store({ state: { ... }, mutations: { [SOME_MUTATION] (state) { } } })
|
Mutation 必须时同步函数
因为在任何回调函数中进行的状态的改变都是不可追踪的。
在组件中提交Mutation
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' }) } }
|
Action
Action 类似于 mutation,不同在于:
- Action提交的是mutation,而不是直接更改状态。
- Action可以包含任意异步操作。
注册Action
Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象,因此你可以调用 context.commit
提交一个 mutation,或者通过 context.state
和 context.getters
来获取 state 和 getters。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| const store = new Vuex.Store({ state: { count: 0 }, mutations: { increment (state) { state.count++ } }, actions: { increment (context) { context.commit('increment') } } })
|
使用ES6简化代码
1 2 3 4 5
| actions: { increment ({ commit }) { commit('increment') } }
|
分发Action
Action 通过 store.dispatch
方法触发:
1
| store.dispatch('increment')
|
购物车实例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| actions: { checkout ({ commit, state }, products) { const savedCartItems = [...state.cart.added] commit(types.CHECKOUT_REQUEST) shop.buyProducts( products, () => commit(types.CHECKOUT_SUCCESS), () => commit(types.CHECKOUT_FAILURE, savedCartItems) ) } }
|
Module
为了避免store对象变得臃肿,vuex允许我们将store划分为模块(module),每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割:
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
|