初识vue 2.0(8):vuex组件通信进阶

主要讲三部分内容:

  1. vuex模块化
  2. vuex命名空间
  3. mutations和actions

模块化

由于使用单一状态树,应用的所有状态会集中到一个比较大的对象,当应用变得非常复杂时,store 对象就有可能变得相当臃肿。

为了解决以上问题,Vuex 允许我们将 store 分割成模块(module),每个模块拥有自己的 state、mutation、action、getter。

因此,创建一个store目录,用来存储状态。

store/
|_ index.js
|_ helloModule.js
|_ gameModule.js

在index.js中导出组件,并在main.js中注册
index.js

/**
 * 状态注册
 */
import helloState from './helloModule.js'
import gameState from './gameModule.js'

export const modules = {
    modules: {
        helloState,
        gameState
    }
}

main.js

// ...
import { modules } from './store'
Vue.use(Vuex)

//集中状态管理
const store = new Vuex.Store(modules);

new Vue({
  el: '#app',
  store,//我在这儿
  template: '<App/>',
  components: { App }
})

命名空间

在命名空间出现之前,Module只是将状态分开,mutations或actions却没有分开。在调用的时候,如果采用一样的命名,在调用时就都会被执行。

因此大家一般将mutations或actions中的方法名抽象成常量,保存在单独的文件中,以避免命名污染。

有了命名空间之后,只要设置 namespaced: true,模块间的方法便相互独立,互不影响,在语法上,也会稍有修改。

helloModule.js

/* global module:true */
export default module = {
    // 开启命名空间
    namespaced: true,
    // 定义状态
    state: {
        msg: '我是Hello模块'
    },
    // 获取状态
    getters: {
        msg: (state) => (txt) => {
            return txt + state.msg // 接受传参
        }
    },
    // 改变状态
    mutations: {
        // 包含异步修改状态
        setMsg (state, msg) {
            state.msg = msg
            setTimeout(() => {
                state.msg = 'mutations修改成功' // 使用commit直接调用此异步方法,能达到修改数据的目的,最终状态没办法追踪
            }, 1000)
        },
        // 不包含异步修改状态
        setMsg2 (state, msg) {
            state.msg = msg
        }
    },
    actions: {
        // 异步修改状态
        setMsg (context, msg) {
            context.commit('setMsg2', msg)
            setTimeout(() => {
                context.commit('setMsg2', 'actions修改成功') // 使用dispatch调用,此异步状态修改可以追踪
            }, 1000)
        }
    }
}

gameModule.js 略

mutations和actions

为什么说mutation只能同步,而action通过commit,可以异步执行mutation?

官网解释:

现在想象,我们正在 debug 一个 app 并且观察 devtool 中的 mutation 日志。每一条 mutation 被记录,devtools 都需要捕捉到前一状态和后一状态的快照。然而,在上面的例子中 mutation 中的异步函数中的回调让这不可能完成:因为当 mutation 触发的时候,回调函数还没有被调用,devtools 不知道什么时候回调函数实际上被调用——实质上任何在回调函数中进行的状态的改变都是不可追踪的。

在 mutation 中混合异步调用会导致你的程序很难调试。例如,当你调用了两个包含异步回调的 mutation 来改变状态,你怎么知道什么时候回调和哪个先回调呢?这就是为什么我们要区分这两个概念。在 Vuex 中,mutation 都是同步事务。

也就是说使用commit调用mutations的方法中,包含异步修改状态的操作,也是能执行成功的;

但是在debug过程中,devtools捕捉不到异步修改的状态的快照,导致调试困难;

因此官方提供了dispatch调用actions的方法来完成异步操作。

并且可以使用dispatch返回promise对象,在组件中完成then操作。

Hello.vue

<template>
<div class="hello">
    <h2>{{ msg }}</h2>
    <button @click="answer">修改</button>
    <button @click="show">查看</button>
</div>
</template>
<script>
export default {
    name: 'hello',
    data () {
        return {
            newMsg:"修改中"
        }
    },
    computed: {
        msg: function () {
            return this.$store.state.helloState.msg
        }
    },
    methods: {
        answer () {
            this.$store.dispatch('helloState/setMsg',this.newMsg);
        },
        show () {
            alert(this.$store.getters['helloState/msg']('查看内容是:'));
        }
    }
}
</script>
<style>
.hello{
  background-color:#E1FFFF;
}
</style>

组件绑定的辅助函数

也就是 mapState,mapMutations,mapGetters、mapActions 这些,一般是可以看作简化语法的语法糖,有机会再详细讲讲。
使用mapState获取状态的简单实例:
修改Hello.vue

import {mapState} from 'vuex';
export default {

    // ...
    
    computed: {      
       ...mapState ({
          msg:state => state.helloState.msg
        })
    },
}

 

posted @ 2018-10-12 18:42  phptree  阅读(163)  评论(0编辑  收藏  举报