1. 程式人生 > >vuex的mapState mapActions mapMutations mapGetters在模組module使用詳解

vuex的mapState mapActions mapMutations mapGetters在模組module使用詳解

我們使用主要是為了簡潔自己的程式碼,
沒用這些方法之前我們的程式碼可能是這樣的(這裡用使用了modules的來舉例子,沒有module的使用更簡單,這裡的module為pim),mutation和action的使用方式一致就不單獨舉例子了。

export default {
    computed: {
        count(){
            return this.$store.state.pim.count;
        },
        newCount(){
            return this.$store.getters['pim/newCount'];
        }
    },
    methods: {
        getList(params){
            return this.$store.dispatch('pim/getList', params);
        }
    }
}

使用了mapState mapActions mapMutations mapGetters程式碼會顯得簡單很多

import {mapState, mapActions, mapMutations, mapGetters}
export default {
    computed: {
        ...mapState('pim', {
            count: state => state.count
        }),
        ...mapGetters('pim', ['newCount'],
    },
    methods: {
        ...mapActions('pim', ['getList']),
    }
}

是不是簡潔多了
但是有個問題
看mapState很容易看出我們是把 pim的state裡面的count對映成當前this下面的count,所以我們也可以將它對映成count2。但是mapGetters、mapActions、mapMutations怎麼辦,直接一個[]是很爽,哈哈。
但是如果pim的store裡面的命名跟我當前vue例項裡面的重複了呢?比如我想把actions裡面的getList對映成vue例項裡面的fetchList方法,而不是也叫getList呢
對於mapActions官網是這麼講的。

...mapActions([
    'some/nested/module/foo', // -> this['some/nested/module/foo']()
    'some/nested/module/bar' // -> this['some/nested/module/bar']()
])

或者

...mapActions('some/nested/module', [
    'foo', // -> this.foo()
    'bar' // -> this.bar()
])

一般情況下使用是夠用的,但是對於我們解決上面提到的命名重複的問題還是沒有幫助。。。
很多網上介紹mapState mapActions mapMutations mapGetters的文章也有意無意的沒有講。
我們就只能看看vuex裡面的原始碼了,看看mapActions這些方法是怎麼解析傳參的。

var mapActions = normalizeNamespace(function (namespace, actions) {
  var res = {};
  normalizeMap(actions).forEach(function (ref) {
    var key = ref.key;
    var val = ref.val;

    res[key] = function mappedAction () {
      var args = [], len = arguments.length;
      while ( len-- ) args[ len ] = arguments[ len ];

      var dispatch = this.$store.dispatch;
      if (namespace) {
        var module = getModuleByNamespace(this.$store, 'mapActions', namespace);
        if (!module) {
          return
        }
        dispatch = module.context.dispatch;
      }
      return typeof val === 'function'
        ? val.apply(this, [dispatch].concat(args))
        : dispatch.apply(this.$store, [val].concat(args))
    };
  });
  return res
});

在mapActions(mapState mapMutations mapGetters類似)一開始會呼叫一個叫normalizeMap的方法。
我們接著看看normalizeMap的方法

function normalizeMap (map) {
  return Array.isArray(map)
    ? map.map(function (key) { return ({ key: key, val: key }); })
    : Object.keys(map).map(function (key) { return ({ key: key, val: map[key] }); })
}

原來就是它在處理我們傳入的第二個引數['getList']normalizeMap會把入參轉化成裝著{key: 'getList', val: 'getList'}的陣列,我們可以看到如果傳入的不是陣列的話,normalizeMap會把入參當做物件來處理,依然把物件轉化為{key: xxx, val: ***}的形式,最後已陣列返回,所以要解決上面的問題我們在mapActions的第二個引數傳入一個物件就行了,我們已經離成功很近了,現在有個小問題,這個物件的key是getList還是fetchList呢???
這是我們就得回到mapActions的原始碼了,看看最終執行的是key還是val了?

return typeof val === 'function'
        ? val.apply(this, [dispatch].concat(args))
        : dispatch.apply(this.$store, [val].concat(args))

真正執行的actions的是根據val,所以我們的問題有答案了

methods: {
        ...mapActions('pim', {
            fetchList: 'getList'
        }),
}

這樣我們就把actions裡面的getList對映成了vue例項裡面的fetchList方法了。
細心的童鞋應該發現了typeof val === 'function',所以我們還可以這樣用

methods: {
        ...mapActions('pim', {
            fetchList(dispatch, params){
                dispatch('getList', params);
            }
        }),
}

這樣也是把getList對映成了fetchList方法了。
相信這次應該講的很詳細了吧,希望對大家有用。