一、更改Vuex的store中的状态的唯一方法是提交mutation。Vuex中的mutation非常类似于事件:每个mutation都有一个字符串的事件类型和一个回调函数,这个回调函数就是我们实际进行状态更改的地方,并且他会接受state作为第一个参数。
1、提交载荷
可以向store.commit传入额外的参数,即mutation的载荷
mutations:{
increment(state,n){
state.count += n
}
}
store.commit('increment',10)
大多数情况下,载荷应该是一个对象,这样可以包含多个字段并且记录的mutation会更易读
mutations:{
increment (state,payload){
state.count+=payload.amount
}
}
store.commit('increment',{amount:10})
2、对象风格的提交方式
提交mutation的另一种方式是直接使用包含type属性的对象
store.commit({
type:'increment',
amount:10
})
当使用对象风格的提交方式,整个对象都作为载荷传给mutation函数,因此handler保持不变
mutations:{
increment(state,payload){
state.count += payload.amount
}
}
3、mutation需遵守Vue的响应规则
既然Vuex的store中的状态是响应式的,那么当我们变更状态时,监视状态的Vue组件也会自动更新。意味着Vuex中的mutation也需要与使用Vue一样遵守一些注意事项
*最好提前在你的store中初始化好所有所需的属性
*当需要在对象上添加新属性时,应该使用Vue.set(obj,'newProp',123)或者
以新对象替换老对象,例如 利用对象展开运算符
state.obj = { ...state.obj, newProp:123 }
4、使用常量替代mutation事件类型
mutations:{
[SOME_MUTATION](state){
}
}
5、mutation必须是同步函数
6、在组件中提交mutation
可以在组件中使用this.$store.commit('xxx')提交mutation,或者使用mapMutations辅助函数将组件中的methods映射为store.commit调用
import { mapMutations } from 'vuex'
export default {
methods: {
...mapMutations(
[
'increment', //将this.increment()映射为this.$store.commit('increment')
//mapMutations也支持载荷
'incrementBy' //将this.incrementBy(amount)映射为this.$store.commit('incrementBy',amount)
]
),
...mapMutations({
add:'increment' //将this.add()映射为this.$store.commit('increment')
})
}
}
二、Action
1、action类似于mutation,然而action提交的是mutation,而不是直接变更状态;action可以包含任意异步操作
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment (state){
state.count++
}
},
actions:{
increment (context) {
context.commit('increment')
}
}
})
action函数接受一个与store实例具有相同方法和属性的context对象,因此你可以调用context.commit提交一个mutation,或者通过context.state和context.getters来获取state和getters。
实践中,我们会经常用到ES2015的参数解构来简化代码
actions: {
increment ({commit}){
commit('increment')
}
}
2、分发Action
action通过store.dispatch方法触发
store.dispatch('increment')
由于mutation必须同步执行,直接分发mutation是不可以的,而action不会受限制,我们可以在action内部执行任意异步操作
actions :{
incrementAsync({commit}){
setTimeout(()=>{
commit('increment')
},1000)
}
}
action支持同样的载荷方式和对象进行分发
store.dispatch('incrementAsync',{
amount: 10
})
store.dispatch({
type:'incrementAsync',
amount" 10
})
3、在组件中分发action
在组件中使用this.$store.dispatch('xxxx')分发action,或者使用mapActions辅助函数组件的methods映射为store.dispatch调用(需要先在根节点注入store)
import { mapActions } from 'vuex'
export default {
methods :{
...mapActions([
'increment', //将 this.increment() 映射为 this.$store.dispatch('increment')
//mapActions 也支持载荷
'incrementBy' //将 this.incrementBy(amount) 映射为 this.$store.dispatch('incrementBy',amount)
]),
...mapActions({
add: 'increment' //将this.add() 映射为 'this.$store.dispatch('increment')'
})
}
}
4、组合action
store.dispatch可以处理被触发的action的处理函数返回的promise,并且store.dispatch仍旧返回promise
actions: {
actionA({ commit }){
return new Promise((resolve, reject)=>{
setTimeout(()=>{
commit('someMutation')
resolve()
}, 1000)
})
}
}
可以这样
store.dispatch('actionA').then(()=>{
//...
})
在另外一个action中也可以
action: {
actionB({ dispatch, commit}){
return dispatch('actionA').then(()=>{
commit('someOtherMutation')
})
}
}
最后可以利用async和await进行组合action
//假设getData() 和 getOtherData() 返回的是Promise
actions: {
async actionA ({ commit }) {
commit('gotData', await getData())
},
async actionB ({ dispatch, commit }) {
await dispatch('actionA')
commit('gotOtherData', await getOtherData())
}
}