Vuex之Getters詳解

原文地址: https://www.jeremyjone.com/543/, 轉載請註明


file

作爲Vue的狀態管理工具,Vuex的使用率相當之高。Vuex具有4個屬性,state,getters,actions,和mutations。

今天來討論一下getters。它相當於vue的computed計算屬性。每當state中的值變化時,它也會自動更新。這個在我們需要那些稍微對state中的屬性進行改造的屬性時很有幫助。在實際生產中,我們會大量使用getters,而state會相對較少。

getters的基本用法,直接調用

首先在根目錄下創建一個store.js

import Vue from "vue";
import Vuex from "vuex";

Vue.use(Vuex);

// 狀態對象
const state = {
  myList: ["a", "b", "c", "d", "e"]
};

// getters計算屬性對象
const getters = {
  getObjByIndex(state): {
    return function(index) {
      return state.myList[index];
    };
  }
};

// 包含多個用於更新state屬性的函數的對象
const mutations = {};

// 包含多個事件回調函數的對象
const actions = {};

export default new Vuex.Store({
  state,
  getters,
  mutations,
  actions
})

然後我們在main.js中引用store,並添加到Vue實例中:

import store from "@/store";

new Vue({
  store,  // 將store對象添加到Vue實例
  render: h => h(App)
}).$mount("#app");

這樣就完成了最簡單的Vuex加載。

調用方案

加載之後,我們就可以在任何Vue組件中使用store,具體方法:

this.$store.getters["getObjByIndex"](0)  // 或 this.$store.getters.getObjByIndex(0)

因爲JavaScript的對象允許我們使用點的方式或者中括號的方式調用對象內容,所以這兩種方式都可以調出getters中的屬性信息。

  • **注意:**我這裏使用了閉包的形態,因爲在getters中是屬性,不是函數,所以我們不能直接傳參調用,但是在實際使用中我們經常需要一些類似idindex這樣的參數來調用某一個序列中的某一個值。爲了解決這個問題,可以使用閉包的方案,具體閉包的功能這裏不贅述。

因爲Vuexstore本身就是一個對象管理,我們都可以通過直接調用的方式來操作。但是每一次都要寫this.$store.getters.xxx這種形式真的很麻煩,有沒有簡單的方式呢?Vuex給了我們很好的解決方案:mapGetters

getters的進階用法,使用mapGetters簡化代碼

對於Vue的組件來說,我們可以使用mapGetters函數,具體方法如下:

先看用法

mapGetters是官方提供的map系列函數中的一個,它會直接返回一個對象,將我們需要的 對象 / 函數 直接加載到組件中。

單store

假設我們還是使用上述創建的store,那麼它在Vue組件中可以這樣使用:

import { mapGetters } from "vuex";
export default {
    computed: {
	    ...mapGetters(["getObjByIndex"]);  // 導入getters的屬性
	}
}

這樣就可以在這個Vue組件中使用這個屬性了。

getObjByIndex(0); // 會直接取值

分模塊store

如果我們的項目很大,單模塊的store完全不能滿足我們的需求,這個時候就需要分模塊。

再比如我們現在有一個叫myStore模塊的store

const state = {
  myList: []
};

const getters = {
  getObjByIndex(state): {
    return function(index) {
      return state.myList[index];
    };
  }
};

const mutations = {};

const actions = {};

export const myStore = {
  namespaced: true,
  state,
  getters,
  actions,
  mutations
};

該倉庫的模塊名爲myStore,繼續導入到Vue組件中:

import { mapGetters } from "vuex";

export default {
    computed: {
	    // 這個時候就需要在導入時添加上模塊名
	    ...mapGetters("myStore", ["getObjByIndex"]);
	}
}

重命名

如果想重命名該屬性,可以使用如下語句,這個對於所有模塊都是一樣的:

import { mapGetters } from "vuex";

export default {
    computed: {
	    // 對屬性重命名,這樣我們就可以在該組件中使用 getMyObj 了。
	    ...mapGetters("myStore", {getMyObj: "getObjByIndex"});
	}
}

深入理解

爲何我們可以這樣方便的使用mapGetters,我們可以通過源碼來找尋答案:

源碼很短:

/**
 * Reduce the code which written in Vue.js for getting the getters
 * @param {String} [namespace] - Module's namespace
 * @param {Object|Array} getters
 * @return {Object}
 */
var mapGetters = normalizeNamespace(function (namespace, getters) {
  var res = {};
  normalizeMap(getters).forEach(function (ref) {
    var key = ref.key;
    var val = ref.val;

    // The namespace has been mutated by normalizeNamespace
    val = namespace + val;
    res[key] = function mappedGetter () {
      if (namespace && !getModuleByNamespace(this.$store, 'mapGetters', namespace)) {
        return
      }
      if (!(val in this.$store.getters)) {
        console.error(("[vuex] unknown getter: " + val));
        return
      }
      return this.$store.getters[val]
    };
    // mark vuex getter for devtools
    res[key].vuex = true;
  });
  return res
});
具體來看

1、首先調用了通用的函數normalizeNamespace,而這個函數就是將傳入的改成namespace/getters的分割樣式,如果沒有namespace,那麼直接返回getters,具體函數如下:

function normalizeNamespace (fn) {
  return function (namespace, map) {
    if (typeof namespace !== 'string') {
      map = namespace;
      namespace = '';
    } else if (namespace.charAt(namespace.length - 1) !== '/') {
      namespace += '/';
    }
    return fn(namespace, map)
  }
}

2、迭代函數normalizeMap只是將輸入的getters對應成store的內部屬性,具體函數如下:

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] });
  })
}

這段函數也說明了爲什麼我們可以使用對象來更改名稱,它依舊會映射我們傳入的value

3、查找屬性。之後的代碼就很簡單了,就是簡單的判斷+查找,如果找到對應的屬性,最後返回 this.$store.getters[val]

這就是mapGetters的大體工作流程。

學以致用

看過源碼,那麼我們試着不用mapGetters來調用。聽起來沒什麼用,但是實際應用中,也會經常使用該方法,比如在js模型中,我們就需要手動調用。

首先引用store

import store from "@/store";

然後直接使用store調用一開始我們定義的屬性:

var myObj = store.getters["myStore/getObjByIndex"]

已經成功調取,是不是很方便。

發佈了96 篇原創文章 · 獲贊 30 · 訪問量 10萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章