Vuex Action

Action 类似于 mutation,不同在于:

  • Action 提交的是 mutation,而不是直接变更状态。
  • Action 可以包含任意异步操作

Action 函数接受一个 context 对象【与 store 实例具有相同方法和属性】context 对象不是 store 实例本身

你可以调用 context.commit 提交一个 mutation,

或者通过 context.statecontext.getters 来获取 state 和 getters。

index.js中添加:

actions: {
    incrementAsync(context) {
        context.commit('increment');
        //context.state.count
        //context.getters.countCache
    },
//实践中,我们会经常用到 ES2015 的 参数解构来简化代码(特别是我们需要调用 commit 很多次的时候):
    decrementAsync({commit}) {
        commit('decrement');
    },
//实践中,我们会经常用到 ES2015 的 参数解构来简化代码(特别是我们需要调用 commit 很多次的时候):
    incrementAsyncDelay({commit}) {
        setTimeout(() => {
            commit('increment');
        }, 1000);//可以在 action 内部执行异步操作
    },
// 用到载荷
    decrementAsyncDelay(context, payload) {
        setTimeout(() => {
            console.log(payload);
            context.commit('decrement');
        }, 1000);//可以在 action 内部执行异步操作
    },
},

分发 Action

Action 通过 store.dispatch 方法触发:

store.dispatch('increment')

通过 载荷方式进行分发:

// 以载荷形式分发
store.dispatch('incrementAsync', {
  amount: 10
})

通过 对象方式进行分发:

// 以对象形式分发
store.dispatch({
  type: 'incrementAsync',
  amount: 10
})

StoreComponent.vue:

<template>
    <div>
        <button @click="increment"> {{count}}</button>
        <button @click="decrement"> {{count}}</button>
        <span> Plus one: {{ countPlus }}</span>
        <span> Length:   {{ countLength}}</span>
        <span> Plus one Length:   {{ countPlusLength}}</span>
        <span> countAndCountPlusCache:   {{ countPCountPlusCache}}</span>
        <span> countAndCountPlusFunc:   {{ countPCountPlusFunc}}</span>
        <div>
            <span> countCache:   {{ countCa}}</span>
            <span> countFunc:   {{ countFu(12)}}</span>
        </div>

        <div>
            <table>
                <tr>
                    <th>Product Name</th>
                    <th>Product Count</th>
                    <th>Product Price</th>
                    <th>Product Total</th>
                </tr>
                <tr>
                    <th>{{pName}}</th>
                    <th>{{count}}</th>
                    <th>{{pPrice}}</th>
                    <th>{{pTotal}}</th>
                </tr>
            </table>
        </div>
        <div>
            <input type="text" v-model="productName">
            <input type="text" v-model="productPrice">
            <button @click="calculate({
                type: 'calculate',
                price: productPrice,
                name: productName,})">Calculate
            </button>
            <button @click="incrementAsync">Increment Async</button>
            <button @click="decrementAsync">Decrement Async</button>
            <button @click="incrementAsyncDelay">Increment Async Delay</button>
            <button @click="decrementAsyncDelay('decrement test')">Decrement Async Delay</button>
        </div>
    </div>
</template>

<script>
    import {mapState} from 'vuex';
    import {mapGetters} from 'vuex';
    import {mapMutations} from 'vuex';
    import {mapActions} from 'vuex';

    export default {
        name: "StoreComponent",
        data: function () {
            return {
                productName: '',
                productPrice: 0,
            }
        },
        // computed: {
        //     count() {
        //         return this.$store.state.count;
        //     },
        //
        // },
        computed: {
            countPlusLength() {
                return this.countPlus.toString().length;
            },
            countPCountPlusCache() {
                return this.$store.getters.countCache;
            },
            countPCountPlusFunc() {
                return this.$store.getters.countFunc(2);
            },
            ...mapState({
                count: state => state.count,

                countPlus: 'countPlus',

                countLength(state) {
                    return state.countLength;
                },
                pName: 'productName',
                pPrice: 'productPrice',
                pTotal: 'productTotal',

            }),
            // 使用对象展开运算符将 getter 混入 computed 对象中
            // ...mapGetters([
            //     'countCache',
            //     'countFunc',
            // ]),


            ...mapGetters({
                // 把 `this.countCa` 映射为 `this.$store.getters.countCache`
                countCa: 'countCache',
                // 把 `this.countFu` 映射为 `this.$store.getters.countFunc`
                countFu: 'countFunc',
            }),
        },
        // computed: mapState([
        //     'count',
        //     'countPlus',
        //     'countLength',
        // ]),
        methods: {
            increment() {
                this.$store.commit('increment');
            },
            decrement() {
                this.$store.commit('decrement');
            },
            // calculate() {
            //     let payload = {
            //         price: this.productPrice,
            //         name: this.productName,
            //     };
            //     // this.$store.commit('calculate', payload);
            //
            //     // this.$store.commit({
            //     //     type: 'calculate',
            //     //     price: this.productPrice,
            //     //     name: this.productName,
            //     // });
            // },
            ...mapMutations([
                'calculate',
            ]),
            incrementAsync() {
//Action 通过 store.dispatch 方法触发
                this.$store.dispatch('incrementAsync');
            },
//mapActions 辅助函数
            ...mapActions([
                // 'incrementAsync',
                'decrementAsync',
                'incrementAsyncDelay',
                'decrementAsyncDelay',
            ]),
        }
    }
</script>

<style scoped>

</style>

效果:

vue.test vuex action

组合 Action

Action 通常是异步的,那么如何知道 action 什么时候结束呢?

更重要的是,我们如何才能组合多个 action,以处理更加复杂的异步流程?

首先, store.dispatch 可以处理被触发的 action 的处理函数返回的 Promise,并且 store.dispatch 仍旧返回 Promise:

类似于C#中返回的Task;

index.js:


import Vue from 'vue';
import 'es6-promise/auto'
import Vuex from 'vuex';

Vue.use(Vuex);

const store = new Vuex.Store({
    state: {
        count: 0,
        countPlus: 1,
        countLength: 1,
        productName: '',
        productPrice: 0,
        productTotal: 0,
    },
    getters: {
        countCache: function (state) {
            return state.count + state.countPlus;
        },
        countFunc: function (state) {
            return function (num) {
                return state.countPlus > num;
            }
        }

    },
    mutations: {
        increment(state) {
            state.count++;
            state.countPlus = state.count + 1;
            state.countLength = state.count.toString().length;
        },
        decrement(state) {
            state.count--;
            state.countPlus = state.count + 1;
            state.countLength = state.count.toString().length;
        },
        calculate(state, payload) {
            state.productPrice = payload.price;
            state.productName = payload.name;
            state.productTotal = state.productPrice * state.count;
        },
    },
    actions: {
        incrementAsync(context) {
            context.commit('increment');
            //context.state.count
            //context.getters.countCache
        },
        decrementAsync({commit}) {
            commit('decrement');
        },
        async incrementAsyncDelay({commit}) {
            setTimeout(() => {
                commit('increment');
            }, 1000);
        },
        async decrementAsyncDelay(context, payload) {
            setTimeout(() => {
                console.log(payload);
                context.commit('decrement');
            }, 1000);
        },
        async comboAsyncDelay({dispatch, commit}) {
            await dispatch('incrementAsyncDelay');
            commit('decrement', await setTimeout(() => {
                console.log('another task');
            }, 1000));
        },
    },
});
export default store;

主要是:

批注 2020-04-24 204315

添加了async标识,await异步操作。

StoreComponent.vue:

<template>
    <div>
        <button @click="increment"> {{count}}</button>
        <button @click="decrement"> {{count}}</button>
        <span> Plus one: {{ countPlus }}</span>
        <span> Length:   {{ countLength}}</span>
        <span> Plus one Length:   {{ countPlusLength}}</span>
        <span> countAndCountPlusCache:   {{ countPCountPlusCache}}</span>
        <span> countAndCountPlusFunc:   {{ countPCountPlusFunc}}</span>
        <div>
            <span> countCache:   {{ countCa}}</span>
            <span> countFunc:   {{ countFu(12)}}</span>
        </div>

        <div>
            <table>
                <tr>
                    <th>Product Name</th>
                    <th>Product Count</th>
                    <th>Product Price</th>
                    <th>Product Total</th>
                </tr>
                <tr>
                    <th>{{pName}}</th>
                    <th>{{count}}</th>
                    <th>{{pPrice}}</th>
                    <th>{{pTotal}}</th>
                </tr>
            </table>
        </div>
        <div>
            <input type="text" v-model="productName">
            <input type="text" v-model="productPrice">
            <button @click="calculate({
                type: 'calculate',
                price: productPrice,
                name: productName,})">Calculate
            </button>
            <button @click="incrementAsync">Increment Async</button>
            <button @click="decrementAsync">Decrement Async</button>
            <button @click="incrementAsyncDelay">Increment Async Delay</button>
            <button @click="decrementAsyncDelay('decrement test')">Decrement Async Delay</button>
            <button @click="comboAsyncDelay">Combo Async Delay</button>
        </div>
    </div>
</template>

<script>
    import {mapState} from 'vuex';
    import {mapGetters} from 'vuex';
    import {mapMutations} from 'vuex';
    import {mapActions} from 'vuex';

    export default {
        name: "StoreComponent",
        data: function () {
            return {
                productName: '',
                productPrice: 0,
            }
        },
        // computed: {
        //     count() {
        //         return this.$store.state.count;
        //     },
        //
        // },
        computed: {
            countPlusLength() {
                return this.countPlus.toString().length;
            },
            countPCountPlusCache() {
                return this.$store.getters.countCache;
            },
            countPCountPlusFunc() {
                return this.$store.getters.countFunc(2);
            },
            ...mapState({
                count: state => state.count,

                countPlus: 'countPlus',

                countLength(state) {
                    return state.countLength;
                },
                pName: 'productName',
                pPrice: 'productPrice',
                pTotal: 'productTotal',

            }),
            // 使用对象展开运算符将 getter 混入 computed 对象中
            // ...mapGetters([
            //     'countCache',
            //     'countFunc',
            // ]),


            ...mapGetters({
                // 把 `this.countCa` 映射为 `this.$store.getters.countCache`
                countCa: 'countCache',
                // 把 `this.countFu` 映射为 `this.$store.getters.countFunc`
                countFu: 'countFunc',
            }),
        },
        // computed: mapState([
        //     'count',
        //     'countPlus',
        //     'countLength',
        // ]),
        methods: {
            increment() {
                this.$store.commit('increment');
            },
            decrement() {
                this.$store.commit('decrement');
            },
            // calculate() {
            //     let payload = {
            //         price: this.productPrice,
            //         name: this.productName,
            //     };
            //     // this.$store.commit('calculate', payload);
            //
            //     // this.$store.commit({
            //     //     type: 'calculate',
            //     //     price: this.productPrice,
            //     //     name: this.productName,
            //     // });
            // },
            ...mapMutations([
                'calculate',
            ]),
            incrementAsync() {
                this.$store.dispatch('incrementAsync').then(() => {
                    console.log('Increment Success!');
                });
            },

            ...mapActions([
                // 'incrementAsync',
                'decrementAsync',
                'incrementAsyncDelay',
                'decrementAsyncDelay',
                'comboAsyncDelay',
            ]),
        }
    }
</script>

<style scoped>

</style>

批注 2020-04-24 204508

以及:

批注 2020-04-24 204553
效果:

vue.test vuex action2

还有一个incrementAsync测试

批注 2020-04-24 205105

原文地址:https://www.cnblogs.com/dzkjz/p/12769894.html