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 是異步的,還有的錯誤處理也都在這里操作。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM