基本的用法就是把一个vue应用中所有的状态都放进store中,然后在computed对象中读取store(这里实际上有两种方式,一是注入store(this.$store.state.xx),二是直接访问全局的store,store.state.xxx)
以上每个状态都需要放到computed中返回,即每个状态都要对应computed中的一个方法,很麻烦,这时候可以使用mapState,提供了简洁的computed对象写法
对于一个比较长的store表达式,如 this.$store.state.todos.filter(todo => todo.done).length,可以放到computed中,也可以放到store的getters对象中。前者属于组件,不方便多组件间的复用,而后者在Store中,store独立于组件,可多组件共用一个store
通过getter可以返回一个值也可以返回一个函数,返回函数有利于state的封装
mapGetters提供了getters的简洁写法
直接修改state的方式是commit一个mutation(处理同步),mapMutataions提供commit mutation的简洁写法。
Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象,因此你可以调用 context.commit
提交一个 mutation,或者通过 context.state
和 context.getters
来获取 state 和 getters。
异步的处理流程:在外部通过store.dispatch发送一个action(执行一个action函数),函数内允许执行异步操作,完成后调用context.commit提交一个mutation,来同步地通知显示结果。因为dispatch返回一个promise,所以也可以在外部注册一个回调函数,来告知异步结果。当外部的注册的函数执行时,也代表这个action(异步操作)已经完成。
action函数也可以写成async的,内部使用await来等待promise。
模块
因为一个vue应用的所有状态都放在了单独的store中,不可避免地会导致store体积较大,可以将store拆分成多个module。module和store具有相同的属性(以上提到的context就是一个module),所以model可以实现多层嵌套(通过modules属性来指定模块):
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 的状态
默认情况下,模块内部的 action、mutation 和 getter 是注册在全局命名空间的——这样使得多个模块能够对同一 mutation 或 action 作出响应:
<script src="https://unpkg.com/vue"></script> <script src="https://unpkg.com/vuex"></script> <script> const moduleA = { mutations: { query:function(){ console.log("query in A") } } } const moduleB = { mutations: { query:function(){ console.log("query in B") } } } const store = new Vuex.Store({ modules: { a: moduleA, b: moduleB } }) store.commit("query"); </script>
以上运行结果,两个模块中的query方法都会被执行。
对于“注册在全局命名空间下”的理解:就像是模块中的内容直接写在了外部的store内一样,而对于多个模块,外部的store就是全部命名空间。这样一来,触发Store.commit当然会执行当下的mutation了。
或者这么说,模块的内容默认是注册到父空间上,store所在的是全局空间(顶层空间),以上的a和b两个模块的父空间刚好就是store全局空间。
如何打破以上这种默认情况,让模块的内容注册到自己的命名空间内呢?只需要在模块内加上一句说明即可:
const moduleB = { namespaced:true, mutations: { query:function(){ console.log("query in B") } } }
重新执行以上代码,B模块中的query就不执行了,而只执行了A中的query。因为多了一句声明,B中的内容已经注册到自己的命名空间下了,而不是全局空间。
那如何执行B中的query呢?只需要在commit的时候加上命名空间:
store.commit("b/query");
运行效果就是仅仅执行了B模块中的query。
模块内获取到的参数,如:state,getters,dispatch、commit等都是指向当前空间,如果想访问根空间,则使用rootXX、或者通过参数指定{root:true},指明要访问全局空间。
以上的模块直接写在了stroe内,属于静态的模块注册。可以通过stroe.registerModule来动态注册模块