白话讲vuex:https://www.jianshu.com/p/120eaf50331c
Vuex五个部分组成:state、getters、mutation、action和module
Mutation
1.只有mutation才能动state,我们不能直接 store.mutations.increment()
来调用,Vuex 规定必须使用 store.commit
来触发对应 type 的方法
2.mutation必须是同步函数
Action
Action 函数接受一个 context
参数,注意,这个参数可不一般,它与 store 实例有着相同的方法和属性
context -> {commit, state}参数解构
Mutation 通过 store.commit
触发,那么 Action 则通过 store.dispatch
方法触发
组合 Action
Action 通常是异步的,那么如何知道 action 什么时候结束呢?更重要的是,我们如何才能组合多个 action,以处理更加复杂的异步流程?
首先,你需要明白
store.dispatch
可以处理被触发的 action 的处理函数返回的 Promise,并且store.dispatch
仍旧返回 Promise:
不知道什么是 Promise 的,可以 戳此了解下。
actions: {
actionA ({ commit }) {
return new Promise((resolve, reject) => {
setTimeout(() => {
commit('someMutation')
resolve()
}, 1000)
})
}
}
调用:
store.dispatch('actionA').then(() => {
// ...
})
当然,也可以这样:
actions: {
// ...
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') // 等待 actionA 完成
commit('gotOtherData', await getOtherData())
}
}
一个
store.dispatch
在不同模块中可以触发多个 action 函数。在这种情况下,只有当所有触发函数完成后,返回的 Promise 才会执行。
我们在实际项目中经常的会遇到这种情况,比如说你现在想要处理 B 事件,但是 B 事件需要一种资源才能进行,而这种资源必须通过 A 事件来获得。这个时候,我们就需要组合 Action 来处理这些事件了。
mapState
通过前面的学习,我们知道,从 store 实例中读取状态最简单的方法就是在计算属性中返回某个状态。
那么,当一个组件需要获取多个状态的时候,怎么办?是不是这样:
export default {
...
computed: {
a () {
return store.state.a
},
b () {
return store.state.b
},
c () {
return store.state.c
},
...
}
}
当然,这样是没问题的,但是总感觉写起来很难受,看起来更难受是吧!既然这么容易我们就感受到了,Vuex 能感受不到吗,能忍得了吗?
绝对不能忍,所以 mapState
辅助函数被创造了出来,用来搞定这个人人为之咬牙切齿的痛点。
// 在单独构建的版本中辅助函数为 Vuex.mapState
import { mapState } from 'vuex'
export default {
// ...
computed: mapState({
// 箭头函数可使代码更简练
a: state => state.a,
b: state => state.b,
c: state => state.c,
// 传字符串参数 'b'
// 等同于 `state => state.b`
bAlias: 'b',
// 为了能够使用 `this` 获取局部状态
// 必须使用常规函数
cInfo (state) {
return state.c + this.info
}
})
}
通过上面的示例,可以了解到,我们可以直接把需要用到的状态全部存放在 mapState
里面进行统一管理,而且还可以取别名,做额外的操作等等。
如果所映射的计算属性名称与 state 的子节点名称相同时,我们还可以更加简化,给 mapState
传一个字符串数组:
computed: mapState([
// 映射 this.a 为 store.state.a
'a',
'b',
'c'
])
因为 computed
这个计算属性接收的是一个对象,所以由上面的示例代码可以看出,mapState
函数返回的是一个对象,现在如果想要和局部的计算属性混合使用的话,可以使用 ES6 的语法这样写来大大简化:
computed: {
localComputed () {
...
},
// 使用对象展开运算符将此对象混入到外部对象中
...mapState({
// ...
})
}
了解了 mapState
辅助函数后,接下来的几个辅助函数的用法也基本上都差不多了,我们继续往下看。
mapGetters
这个和 mapState
基本上没啥区别,简单看下官方的例子,就懂了:
import { mapGetters } from 'vuex'
export default {
// ...
computed: {
...mapGetters([
'doneTodosCount',
'anotherGetter',
// ...
])
}
}
取个别名,那就用对象的形式,以下示例的意思就是把 this.doneCount
映射为 this.$store.getters.doneTodosCount
。
mapGetters({
doneCount: 'doneTodosCount'
})
mapMutations
直接看示例代码:
import { mapMutations } from 'vuex'
export default {
// ...
methods: {
...mapMutations([
// 将 `this.increment()` 映射为
// `this.$store.commit('increment')`
'increment',
// `mapMutations` 也支持载荷:
// 将 `this.incrementBy(amount)` 映射为
// `this.$store.commit('incrementBy', amount)`
'incrementBy'
]),
...mapMutations({
// 将 `this.add()` 映射为
// `this.$store.commit('increment')`
add: 'increment'
})
}
}
简直不要太好用,连载荷也可以直接支持。
mapActions
和 mapMutations
用法一模一样,换个名字即可。
import { mapActions } from 'vuex'
export default {
// ...
methods: {
...mapActions([
// 将 `this.increment()` 映射为
// `this.$store. dispatch('increment')`
'increment',
// `mapActions` 也支持载荷:
// 将 `this.incrementBy(amount)` 映射为
// `this.$store. dispatch('incrementBy', amount)`
'incrementBy'
]),
...mapActions({
// 将 `this.add()` 映射为
// `this.$store. dispatch('increment')`
add: 'increment'
})
}
}
想要在组件中调用,直接 this.xxx
就完了。
Module
Module 其实就承担了部门管理员的角色,而 store 就是老板。
import moduleA from './module/moduleA';
import moduleB from './module/moduleB';
export default new Vuex.Store({
modules: {
moduleA, moduleB,
},
// ...
}
Tips:
通过computed监听Vuex的state 对象中某属性的方法(https://www.cnblogs.com/ysx215/p/11436429.html)
object.assign(targetObject, sourceObj1, sourceObj2....)方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象,返回目标对象。
// 将info这个对象复制到 state.personInfo对象
// 将处理完的state.personInfo对象赋值给data变量
let data = Object.assign(state.personInfo, info);
// 此时state.personInfo里的值改变了,但是引用地址未变
state.personInfo = data;
// 创建一个新的对象,将info,state.personInfo对象复制到新对象中
let data = Object.assign({}, state.personInfo, info);
// 将state.personInfo指向新对象的引用地址
state.personInfo = data;
第一种方法,当state.personInfo中某一属性改变时,并不会触发computed重新渲染,第二种方式是由于地址发生了改变,触发了重新渲染机制!