loading...

0

vuex2.0 基本使用(2) --- mutation 和 action

其他读完大概需要20分钟

  • 发布时间:2017-09-07 14:07 星期四
  • 刘伟波
  • 209
  • 更新于2017-09-07 14:07 星期四

vuex2.0 基本使用(2) --- mutation 和 action

  我们的项目非常简单,当点击+1按钮的时候,count 加1,点击-1按钮的时候,count 减1.

1, mutation

  The only way to actually change state in a Vuex store is by committing a mutation, 在vue 中,只有mutation 才能改变state.  mutation 类似事件,每一个mutation都有一个类型和一个处理函数,因为只有mutation 才能改变state, 所以处理函数自动会获得一个默认参数 state. 所谓的类型其实就是名字,action去comit 一个mutation, 它要指定去commit哪个mutation, 所以mutation至少需要一个名字,commit mutation 之后, 要做什么事情,那就需要给它指定一个处理函数, 类型(名字) + 处理函数就构成了mutation. 现在store.js添加mutation.

复制代码

const store = new Vuex.Store({
    state: {
        count:0
    },
    mutations: {
        // 加1
        increment(state) {
            state.count++;
        },
        // 减1
        decrement(state) {
            state.count--
        }
    }
})

复制代码

  Vue 建议我们mutation 类型用大写常量表示,修改一下,把mutation 类型改为大写

复制代码

mutations: {
        // 加1
        INCREMENT(state) {
            state.count++;
        },
        // 减1
        DECREMENT(state) {
            state.count--
        }
    }

复制代码

2, action

action去commit mutations, 所以还要定义action. store.js 里面添加actions.

复制代码

const store = new Vuex.Store({
    state: {
        count:0
    },
    mutations: {
        // 加1
        INCREMENT(state) {
            state.count++;
        },
        // 减1
        DECREMENT(state) {
            state.count--
        }
    },
    actions: {
        increment(context) {
            context.commit("INCREMENT");
        },
        decrement(context) {
            context.commit("DECREMENT");
        }
    }
})

复制代码

  action 和mutions 的定义方法是类似的,我们要dispatch 一个action, 所以actions 肯定有一个名字,dispatch action 之后它要做事情,就是commit mutation, 所以还要给它指定一个函数。因为要commit mutation ,所以 函数也会自动获得一个默认参数context,  它是一个store 实例,通过它可以获取到store 实例的属性和方法,如 context.state 就会获取到 state 属性, context.commit 就会执行commit命令。

  其实actions 还可以简写一下, 因为函数的参数是一个对象,函数中用的是对象中一个方法,我们可以通过对象的解构赋值直接获取到该方法。修改一下 actions

复制代码

actions: {
        increment({commit}){
            commit("INCREMENT")
        },
        decrement({commit}){
            commit("DECREMENT")
        }
    }

复制代码

3, dispatch  action

  现在就剩下dispatch action 了。什么时候dispatch action 呢? 只有当我们点击按钮的时候. 给按钮添加click 事件,在click 事件处理函数的中dispatch action.

  打开increment.vue 组件,给两个按钮添加click 事件。

复制代码

<template>
    <div>
        <button @click="increment">+1</button>
        <button @click="decrement">-1</button>
    </div>
</template>

<script>
    export default {
        methods: {
            increment(){
                this.$store.dispatch("increment");
            },
            decrement() {
                this.$store.dispatch("decrement")
            }
        }
    }
</script>

复制代码

  其实像上面dispatch action 比较麻烦,如果有10 个按钮,我们要写10 个函数,且存在大量的重复,并且我们的事件处理函数名字和action的名字是一样的,这时vue  提供了mapAction 函数,它和mapState  是一样的,把我们的 action 直接映射到store 里面的action中。

  像这种组件中的事件处理函数名字和action的名字是相同的,直接把 事件处理函数名字放到一个数组中。组件中的methods 修改如下:

复制代码

<script>
    import {mapActions} from "vuex";
    export default {
        methods: {
            ...mapActions(["increment", "decrement"])
        }
    }
</script>

复制代码

  如果事件处理函数名字和action的名字不同,给mapActions 提供一个对象,对象的属性是事件处理函数名字, 属性值是 对应的dispatch 的action 的名字。

  我们把 +1 按钮的事件处理函数变改为 add,代码如下: 

复制代码

<template>
    <div>
        <button @click="add">+1</button>    <!-- 事件处理函数变为add -->
        <button @click="decrement">-1</button>
    </div>
</template>

<script>
    import {mapActions} from "vuex";
    export default {
        methods: {
            ...mapActions(["decrement"]),

       // mapActions 对应做出改变 ...mapActions({ add: "increment" }) } }

复制代码

这时候我们单击按钮,就可以看到count 发生变化。

通过vuex 传递参数

  很多时候,组件和组件之间还要传递参数,这些都要经过vuex。 在increment 组件内部增加一个输入框和一个按钮,点击按钮的时候,count 增加输入框内的值。

复制代码

<template>
    <div>
        <div>
            <button @click="increment">+1</button>
            <button @click="decrement">-1</button>
        </div>
    // 增加内容 <div> <input type="text" v-model="incrementValue"> <button @click="incrementWithValue">increment</button> </div> </div> </template>

复制代码

  在组件内部dispatch action 的时候,它可以自定义参数,只要参数在它dispatch 的action名称 后面,依次列出来就可以了。 在这里,我们点击按钮的时候,触发一个incrementWithValue  action, 并且带一个参数,就可以这样写 this.$store.dispatch(“incrementWithValue”, value), 整个increment.vue 组件如下:

复制代码

<template>
    <div>
        <div>
            <button @click="increment">+1</button>
            <button @click="decrement">-1</button>
        </div>
        <div>
            <input type="text" v-model="incrementValue">
            <button @click="incrementWithValue">increment</button>
        </div>
    </div>
</template>

<script>
    import {mapActions} from "vuex";
    export default {
        data() {
            return {
                incrementValue: 0
            }
        },
        methods: {
            ...mapActions(["increment","decrement"]),
            incrementWithValue() {
                this.$store.dispatch("incrementWithValue", this.incrementValue)
            }
        }
    }
</script>

复制代码

  同样,actions 和mutations 中的处理函数也是一样,它除了可以得到默认参数外,还可以接受自定义的参数,我们自定义的参数,依次在默认参数后面列出来就可以了。 在store.js中分加增加incrementWithValue action和 INCREMENT_WITH_VALUE mutation 

复制代码

const store = new Vuex.Store({
    state: {
        count:0
    },
    mutations: {
        // 加1
        INCREMENT(state) {
            state.count++;
        },
        // 减1
        DECREMENT(state) {
            state.count--
        },
        INCREMENT_WITH_VALUE(state, value){
            state.count +=value;
        }
    },
    actions: {
        increment({commit}){
            commit("INCREMENT")
        },
        decrement({commit}){
            commit("DECREMENT")
        },
        incrementWithValue({commit}, value){
            commit("INCREMENT_WITH_VALUE",  parseInt(value))
        }
    }
})

复制代码

 错误处理

  当我们给vuex 传参的时候,我们要检测参数的正确性,如果有错误需要进行处理

  action 中如果是同步操作,就用try..catch 语句,组件中使用try…catch, 捕获action中抛出的错误。Increment.vue 组件中,incrementWithValue() 方法中修改如下:

复制代码

methods: {
            ...mapActions(["increment","decrement"]),
            incrementWithValue() {
                 try {
                     this.$store.dispatch("incrementWithValue", this.incrementValue)
                 }catch(error) {
                     alert(error)
                 }
            }
        }

复制代码

  同时store.js 中的action 也进行如下修改:

复制代码

incrementWithValue({commit}, value){
    let intValue = parseInt(value);
    if(isNaN(intValue)){
        throw "Not an Interger"
    }else {
        commit("INCREMENT_WITH_VALUE",  intValue)
    }
}

复制代码

  如果action 中进行的是异步操作,那就需要在回调函数中进行错误处理。

复制代码

incrementWithValue({commit}, value){
      let intValue = parseInt(value)
            setTimeout(function() {

                if(isNaN(intValue)) {
                    alert("Not an Interger")
                }else {    
                    commit("INCREMENT_WITH_VALUE", intValue)
                }
            }, 2000)
        }

复制代码

异步操作给出用户提示信息

  首先,在我们的increment.vue中添加一个提示信息,简单给一个div 进行提示。用户提示信息的显示和隐藏,又涉及到一个状态,我们设为waiting, 需要在state 中进行添加。默认为false, 同时我们组件需要从state 中获取到初始状态。increment.vue 组件修改如下:

复制代码

<template>
    <div>
        <div>
            <button @click="increment">+1</button>
            <button @click="decrement">-1</button>
        </div>
        <div>
            <input type="text" v-model="incrementValue">
            <button @click="incrementWithValue">increment</button>
        </div>
        <!-- 展示信息 -->
        <div v-if ="show">
            waiting 
        </div>
    </div>
</template>

<script>
    import {mapActions} from "vuex";
    export default {
        data() {
            return {
                incrementValue: 0
            }
        },
    // computed 从state 中获取初始状态 computed: { show: function() { return this.$store.state.waiting; } }, methods: { ...mapActions(["increment","decrement"]), incrementWithValue() { this.$store.dispatch("incrementWithValue", this.incrementValue) } } } </script>

复制代码

mutation 去操作状态,所以增加两个muatation, 用于显示和隐藏waiting. action 中去触发这两个mutation. 整个state 如下:

复制代码

const store = new Vuex.Store({
    state: {
        count:0,
        // 新增waiting  状态
        waiting: false
    },
    mutations: {
        // 加1
        INCREMENT(state) {
            state.count++;
        },
        // 减1
        DECREMENT(state) {
            state.count--
        },
        INCREMENT_WITH_VALUE(state, value){
            state.count +=value;
        },
        // 显示和隐藏waiting
        SHOW_WAITING_MESSAGE(state){
            state.waiting = true;
        },
        HIDE_WAITING_MESSAGE(state){
            state.waiting = false;
        }
    },
    actions: {
        increment({commit}){
            commit("INCREMENT")
        },
        decrement({commit}){
            commit("DECREMENT")
        },
        incrementWithValue({commit}, value){
            commit("SHOW_WAITING_MESSAGE");
            let intValue = parseInt(value)
            setTimeout(function() {
                if(isNaN(intValue)) {
                    alert("Not an Interger")
                }else {    
                    commit("HIDE_WAITING_MESSAGE");
                    commit("INCREMENT_WITH_VALUE", intValue)
                }
            }, 2000)
        }
    }
})

复制代码

 注意:

  mutation是同步的,只要comit muation, 它就会立即改变state , 这有利于我们追踪 状态的改变。如果 mution 之后,五分钟才改变state, 那就真不知道state 到底是哪个state了。

  action 是异步的,还有的错误处理也都在这里操作。


你可能感兴趣的文章

    发表评论

    评论支持markdown,评论内容不能超过500字符,如果内容过多或者要及时回复,建议去 segmentfault平台, 也可以来我的直播间来提问。
    关于技术问题或者有啥不懂的都可以留言, 我会定期回复答疑, 也可以来 我的直播间 提问, 推荐最新仓库 前端知识体系, 感謝支持!