vuex3源码注释系列 /src/helper.js mapState,mapMutation,mapGetter,mapAction 源码解析

本文深入解析Vuex3的src/helper.js中mapState、mapMutation、mapGetter和mapAction的源码,揭示它们的工作原理和实现细节,帮助前端开发者更好地理解和使用Vuex进行状态管理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

import {
   
    isObject } from "./util";

/**
 * vuex 中使用的四个辅助函数的来源文件 /src/helpers.js。
 * mapState,
 * mapMutations,
 * mapGetters,
 * mapActions,
 * createNamespacedHelpers
 */

/*
  mapState 经过 调用normalizeNamespace() 之后,返回的结果,这个结果就是个函数。
  我们调用的 mapState 是如下函数:

  return (namespace, map) => {
    //如果第一个参数 namespace 不是字符串。那就认为只有一个参数,该参数是个数组. 如:["user/updateName", "user/updateAge"]
    if (typeof namespace !== "string") {
      //将命名空间数组的数据统一到 map
      map = namespace;
      //设置namepace为空。
      namespace = "";

      //namespace 是 string,如果 namespace 不是以 “/” 结尾,则在尾部添加个 "/"
    } else if (namespace.charAt(namespace.length - 1) !== "/") {
      namespace += "/";
    }
    return fn(namespace, map);
  };
  第一个参数: namespace 是字符串,
  第二个参数:states 是一个数组或者非null的对象。其元素或者value可以是函数。

  ==> 当然最终就是调用了 normalizeNamespace 的第一个参数指向的函数。
  ==> 由于函数内部有 this.$store 的方式,导致必须在 vue 环境下才能使用 mapState。
*/
export const mapState = normalizeNamespace((namespace, states) => {
   
   
  //存储结果的对象,是个 {};
  const res = {
   
   };
  //如果是在开发环境,且如果不是个可用的对象,则报红提示。
  if (__DEV__ && !isValidMap(states)) {
   
   
    console.error(
      "[vuex] mapState: mapper parameter must be either an Array or an Object"
    );
  }

  //将 states 归一化为数组。格式为: [{ key:key, value:value }, ...]
  normalizeMap(states).forEach(({
   
    key, val }) => {
   
   
    /**
     * 这里有一点需要注意:
     * computed: {
     *   ...mapState(["user1/info", "user1/name"]);
     *   ...mapState("user2", ["info", "name"]);
     *   ...mapState({
     *        "info1": "user1/info",
     *        "info2": "user2/info"
     *    })
     *   ...mapState( "user", {
     *        "info1": "info1",
     *        "info2": "info2"
     *    })
     * }
     * 1、mapState 返回的结果是一个对象,对象的中属性key,对应的value都是函数。
     *    (1) 如果是数组,则 key 就是 1,2,3,4...
     *    (2) 在 vue 的 computed 创建时,会被数据劫持,key就是不含有 namespace 的key。
     *    (3) Object.keys( res ).forEach( key=>{
     *          Object.defineProperty( vue, key, {
     *              get(){
     *                 res[key]();
     *              }
     *          })
     *      })
     *       通过数据劫持之后,就做到了 this.info1 就能调用 mappedState() 方法。
     *
     * 2、关于 ...mapState("user", [info(state, getter){}, ...]) 的形式:
     *    info( state, getter ){ ... } 通过该函数的返回值作为结果。
     */
    res[key] = function mappedState() {
   
   
      //注意这个 this 是引入 mapState 页面的 vue 实例。
      //state 存储所有的 options 中的 state 数据。
      let state = this.$store.state;
      //getters 存储所有的 options 中的 getter 数据。
      let getters = this.$store.getters;
      //如果 namespace 存在,则去对应的子 module 查找 state 和 getter。
      //否则就直接在 store 上找 state 和 getter。
      if (namespace) {
   
   
        //通过 namespace 找到指定的 module。
        const module = getModuleByNamespace(this.$store, "mapState", namespace);
        //如果不存在,则返回null。
        if (!module) {
   
   
          return;
        }
        //module.context 就是 store.js 的 local 对象。
        //module.context.state 能通过闭包的方式获取到该module 对应的 namespace,path。
        state = module.context.state;
        //module.context.state 能通过闭包的方式获取到该module 对应的 namespace,path。且会从 store.getters 中获取。
        getters = module.context.getters;
      }
      //如果val 是 mapState( [( state, getters )=>{  }] ) 的 ( state, getters )=>{  }, 则调用该函数获取返回值。
      return typeof val === "function"
        ? val.<
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值