vuex 源码分析_Vuex之Getters详解

作为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中是属性,不是函数,所以我们不能直接传参调用,但是在实际使用中我们经常需要一些类似id,index这样的参数来调用某一个序列中的某一个值。为了解决这个问题,可以使用闭包的方案,具体闭包的功能这里不赘述。

因为Vuex的store本身就是一个对象管理,我们都可以通过直接调用的方式来操作。但是每一次都要写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"]

已经成功调取,是不是很方便。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值