【Vuex 源码学习】第十三篇 - Vuex 辅助函数的实现

297 阅读1分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

本文已参与「掘力星计划」,赢取创作大礼包,挑战创作激励金。


一,前言

上一篇,主要介绍了 Vuex 插件机制的实现,主要涉及以下几个点:

  • Vuex 插件机制分析;
  • Vuex 插件机制核心逻辑实现:plugins 插件注册、subscribe 订阅收集、replaceState 状态替换;

本篇,继续介绍 Vuex 辅助函数的实现;


二,辅助函数的介绍

1,辅助函数的作用

继续以之前的代码作为示例:

<template>
  <div id="app">
    <br> 根模块测试: <br>
    商品数量: {{this.$store.state.num}} 个<br>
    商品单价: 10 元<br>
    订单金额: {{this.$store.getters.getPrice}} 元<br>
    <button @click="$store.commit('changeNum',5)">同步更新:数量+5</button>
    <button @click="$store.dispatch('changeNum',-5)">异步更新:数量-5</button>

    <br> 子模块测试: <br>
    A 模块-商品数量: {{this.$store.state.moduleA.num}} 个<br>
    B 模块-商品数量: {{this.$store.state.moduleB.num}} 个<br>
    C 模块-商品数量: {{this.$store.state.moduleA.moduleC.num}} 个<br>
    <button @click="$store.commit('moduleA/changeNum',5)">A 模块-同步更新:数量+5</button>
    <button @click="$store.commit('moduleB/changeNum',5)">B 模块-同步更新:数量+5</button>
    <button @click="$store.commit('moduleA/moduleC/changeNum',5)">C 模块-同步更新:数量+5</button>
  </div>
</template>

可以发现,在项目使用 Vuex 插件中 State、getter、mutation、action 时,需要通过类似 this.$store.state.num 这样一长串才可以实现,当模块层级较深就会变得更长;这种不太优雅的写法,也会影响到代码的可读性及后续运维;

所以,Vuex 插件提供了一系列辅助函数,用于简化和解决上边的问题;

2,辅助函数功能介绍

Vuex 提供了以下辅助函数:

  • mapState:在组件的 computed 中使用;
  • mapGetters:在组件的 computed 中使用;
  • mapMutations:在组件的 methods 中使用;
  • mapActios:在组件的 methods 中使用;
  • createNamespacedHelpers:获取指定命名空间下的辅助函数;

三,Vuex 辅助函数的使用

使用官网 Vuex 插件提供的辅助函数对示例进行优化

1,辅助函数 mapState

<template>
  <div id="app">
    商品数量: {{num}} 个<br>
  </div>
</template>

<script>
import { mapState } from "vuex";
export default {
  computed: {
    // 写法 1:
    // ...mapState(["num"]),
    // 写法 2:
    ...mapState({
      num: state => state.num,
    })
  }
};
</script>

2,辅助函数 mapGetters

<template>
  <div id="app">
    订单金额: {{getPrice}} 元<br>
  </div>
</template>

<script>
import { mapGetters } from "vuex";
export default {
  computed: {
    // 写法 1:
    // ...mapGetters(["getPrice"]),
    // 写法 2:
    ...mapGetters({
      getPrice: "getPrice"
    })
  }
};
</script>

3,辅助函数 mapMutations

<template>
  <div id="app">
    商品数量: {{num}} 个<br>
    商品单价: 10 元<br>
    订单金额: {{getPrice}} 元<br>
    <button @click="mutationChangeNum(5)">同步更新:数量+5</button>
  </div>
</template>

<script>
import { mapState, mapMutations } from "vuex";
export default {
  computed: {
    ...mapState(["num"]),
  },
  methods: {
    // 写法 1:
    // ...mapMutations(['changeNum']),
    // 写法 2:
    ...mapMutations({
      mutationChangeNum: 'changeNum',
    })
  }
};
</script>

4,辅助函数 mapActions

<template>
  <div id="app">
    <br> 根模块测试: <br>
    商品数量: {{num}} 个<br>
    商品单价: 10 元<br>
    订单金额: {{getPrice}} 元<br>
    <button @click="actionChangeNum(-5)">异步更新:数量-5</button>
  </div>
</template>

<script>
import { mapState, mapActions } from "vuex";
export default {
  computed: {
    ...mapState(["num"]),
  },
  methods: {
    // 写法 1:
    // ...mapActions(['changeNum'])
    // 写法 2:
    ...mapActions({
      actionChangeNum: 'changeNum'
    })
  }
};
</script>

5,辅助函数 createNamespacedHelpers

使用 createNamespacedHelpers 获取指定模块辅助函数,简化 Vuex 使用:

<template>
  <div id="app">
    A 模块-商品数量: {{numA}} 个<br>
    C 模块-商品数量: {{numC}} 个<br>
    <button @click="mutationAChangeNum(5)">A 模块-同步更新:数量+5</button>
    <button @click="mutationCChangeNum(5)">C 模块-同步更新:数量+5</button>
  </div>
</template>

<script>
import { mapState, mapMutations } from "vuex";
import { createNamespacedHelpers } from "vuex";
const { mapState: mapStateA, mapMutations:mapMutationsA } = createNamespacedHelpers('moduleA');
const { mapState: mapStateC, mapMutations:mapMutationsC } = createNamespacedHelpers("moduleA/moduleC");

export default {
  computed: {
    // 写法 1:
    // ...mapState({
    //   numA: state => state.moduleA.num,
    //   numC: state => state.moduleC.num
    // })
    // 写法 2:
    ...mapStateA({
      numA: state => state.num
    }),
    ...mapStateC({
      numC: state => state.num
    })
  },
  methods: {
    // 写法 1:
    // ...mapMutations({
    //   mutationAChangeNum: 'moduleA/changeNum'
    // }),
    // // 写法 2:
    ...mapMutationsA({
      mutationAChangeNum: 'changeNum'
    }),
    ...mapMutationsC({
      mutationCChangeNum: 'changeNum'
    })
  }
};
</script>

四,Vuex 辅助函数的实现

1,辅助函数逻辑分析

辅助函数 mapState、mapActions、mapMutations,通过将 vuex.store 中的属性映射到 vm 实例上,从而实现通过 vm 实例可以直接访问到 vuex.store 中的属性,简化 Vuex 操作;

2,mapState 实现

创建 mapState 方法:根据指定状态名,返回状态对象;

// src/vuex/ helpers.js

/**
 * 根据指定状态名,返回状态对象
 * @param {*} stateArr 指定需要返回的状态名
 * @returns 状态对象
 */
export function mapState(stateArr) {
  let obj = {};
  for (let i = 0; i < stateArr.length; i++) {
    let stateName = stateArr[i];
    obj[stateName] = function () {
      // 从 $store.state 中查找状态名
      return this.$store.state[stateName]
    }
  }
  return obj
}

Vuex 插件导出 mapState 方法:

// src/vuex/index.js

import { Store, install } from './store';

export default {
  Store,
  install
}

export * from './helpers';

其他辅助函数同理,后续补充;

export function mapGetters(gettersArr) {
    let obj = {};
    for (let i = 0; i < gettersArr.length; i++) {
        let gettName = gettersArr[i];
        obj[gettName] = function() {
            return this.$store.getters[gettName]
        }
    }
    return obj
}

五,结尾

本篇,主要介绍了 Vuex 辅助函数的实现,主要涉及以下几个点:

  • Vuex 辅助函数作用和功能介绍;
  • Vuex 辅助函数使用介绍;
  • Vuex 辅助函数原理分析与代码实现;

至此,《Vuex 源码学习笔记》专栏完结,后续将会继续完善扩充;

准备开始下一个源码专栏~