【pinia源码】四、mapHelper API源码解析
前言
【pinia源码】系列文章主要分析pinia的实现原理。该系列文章源码参考pinia v2.0.14。
源码地址:https://github.com/vuejs/pinia
本篇文章将分析mapHelper API的实现。
使用
pinia提供了Vuex中的mapState、mapActions等一些辅助函数。这些函数的定义在packages/pinia/src/mapHelpers.ts中。
mapStore
使用mapStore获取完整的store。
import { mapStores } from 'pinia'
const useUserStore = defineStore('user', {
  // ...
})
const useCartStore = defineStore('cart', {
  // ...
})
export default {
  computed: {
    ...mapStores(useCartStore, useUserStore)
  },
  methods: {
    async buyStuff() {
      if (this.userStore.isAuthenticated()) {
        await this.cartStore.buy()
      }
    },
  },
}mapState、mapGetters、mapActions
使用mapState,获取store.state及state.getter。
mapGetters为mapState的别名。
使用mapAction,获取store.actions。
export default {
  computed: {
    ...mapState(useCounterStore, {
      n: 'count',
      triple: store => store.n * 3,
      doubleN: 'double'
    })
  },
  created() {
    this.add()
    console.log(this.n) // 2
    console.log(this.doubleN) // 4
  },
  methods: {
    ...mapActions(useCounterStore, {
      add: 'increment',
    })
  }
}
export default {
  computed: {
    ...mapState(useCounterStore, [ 'count', 'double' ])
  },
  created() {
    this.add()
    console.log(this.count) // 2
    console.log(this.double) // 4
  },
  methods: {
    ...mapActions(useCounterStore, [ 'add' ])
  }
}mapWritableState
与mapState相似,与mapState不同的是,通过mapWritableState获得的数据,可以直接对其进行修改。
export default defineComponent({
  name: 'Test',
  computed: {
    ...mapWritableState(useCounterStore, [ 'n' ])
  },
  methods: {
    handleClick() {
      this.n++
    }
  }
})mapStore源码
export function mapStores<Stores extends any[]>(
  ...stores: [...Stores]
): _Spread<Stores> {
  // 如果接收的是个数组参数,进行提示
  if (__DEV__ && Array.isArray(stores[0])) {
    console.warn(
      `[🍍]: Directly pass all stores to "mapStores()" without putting them in an array:\n` +
        `Replace\n` +
        `\tmapStores([useAuthStore, useCartStore])\n` +
        `with\n` +
        `\tmapStores(useAuthStore, useCartStore)\n` +
        `This will fail in production if not fixed.`
    )
    // 开发环境下stores取第一个值
    stores = stores[0]
  }
  // 返回一个对象
  return stores.reduce((reduced, useStore) => {
    // reduced的key值:useStore.$id + mapStoreSuffix(默认Store,可使用setMapStoreSuffix进行修改)
    reduced[useStore.$id + mapStoreSuffix] = function (
      this: ComponentPublicInstance
    ) {
      // 使用useStore获取store,在组件中可通过this.$pinia获取pinia
      return useStore(this.$pinia)
    }
    return reduced
  }, {} as _Spread<Stores>)
}mapStores可接收多个useStore函数。
mapStores会对参数进行校验,如果传入的第一个参数为数组,那么在开发环境下会进行提示,并将数组中的第一个值赋给stores,以保证开发环境下能够运行。然后返回一个对象,该对象通过stores.reduce生成,对象的key值是由useStore.$id + mapStoreSuffix组成,对应的value是个函数,在函数中会调用useStore(this.$pinia),返回其结果。
mapState、mapGetters源码
export function mapState<
  Id extends string,
  S extends StateTree,
  G extends _GettersTree<S>,
  A
>(
  useStore: StoreDefinition<Id, S, G, A>,
  keysOrMapper: any
): _MapStateReturn<S, G> | _MapStateObjectReturn<Id, S, G, A> {
  return Array.isArray(keysOrMapper)
    ? keysOrMapper.reduce((reduced, key) => {
        reduced[key] = function (this: ComponentPublicInstance) {
          return useStore(this.$pinia)[key]
        } as () => any
        return reduced
      }, {} as _MapStateReturn<S, G>)
    : Object.keys(keysOrMapper).reduce((reduced, key: string) => {
        reduced[key] = function (this: ComponentPublicInstance) {
          const store = useStore(this.$pinia)
          const storeKey = keysOrMapper[key]
          return typeof storeKey === 'function'
            ? (storeKey as (store: Store<Id, S, G, A>) => any).call(this, store)
            : store[storeKey]
        }
        return reduced
      }, {} as _MapStateObjectReturn<Id, S, G, A>)
}
export const mapGetters = mapStatemapState可以接受两个参数:useStore(一个useStore函数)、keysOrMapper(一个key列表,或map对象)。
mapState会返回一个对象,这个对象的key值是通过keysOrMapper获得的。如果传入keysOrMapper是数组,返回对象的key就是keysOrMapper中的元素,key对应的值是个获取store[key]的函数。 如果keysOrMapper是个对象,返回对象的key是keysOrMapper中的key,key对应的值根据keysOrMapper[key]的类型有所区别,如果keysOrMapper[key]是function,返回结果中对应key的值是一个返回keysOrMapper[key].call(this, store)的函数,否则key对应的是个返回store[keysOrMapper[key]]的函数。
mapGetters同mapState。
mapActions源码
export function mapActions<
  Id extends string,
  S extends StateTree,
  G extends _GettersTree<S>,
  A,
  KeyMapper extends Record<string, keyof A>
>(
  useStore: StoreDefinition<Id, S, G, A>,
  keysOrMapper: Array<keyof A> | KeyMapper
): _MapActionsReturn<A> | _MapActionsObjectReturn<A, KeyMapper> {
  return Array.isArray(keysOrMapper)
    ? keysOrMapper.reduce((reduced, key) => {
        reduced[key] = function (
          this: ComponentPublicInstance,
          ...args: any[]
        ) {
          return useStore(this.$pinia)[key](...args)
        }
        return reduced
      }, {} as _MapActionsReturn<A>)
    : Object.keys(keysOrMapper).reduce((reduced, key: keyof KeyMapper) => {
        reduced[key] = function (
          this: ComponentPublicInstance,
          ...args: any[]
        ) {
          return useStore(this.$pinia)[keysOrMapper[key]](...args)
        }
        return reduced
      }, {} as _MapActionsObjectReturn<A, KeyMapper>)
}mapActions可以接受两个参数:useStore(一个useStore函数)、keysOrMapper(一个key列表,或map对象)。
mapActions返回一个对象。对象中的键通过keysOrMapper获得,如果keysOrMapper是个数组,那么key是数组中的元素,对应的值是函数,这个函数返回对应store[key]()的返回值。如果keysOrMapper是个对象,那么对象中键就是keysOrMapper中的键,对应的值是个函数,这个函数返回store[keysOrMapper[key]]()的返回值。
mapWritableState源码
export function mapWritableState<
  Id extends string,
  S extends StateTree,
  G extends _GettersTree<S>,
  A,
  KeyMapper extends Record<string, keyof S>
>(
  useStore: StoreDefinition<Id, S, G, A>,
  keysOrMapper: Array<keyof S> | KeyMapper
): _MapWritableStateReturn<S> | _MapWritableStateObjectReturn<S, KeyMapper> {
  return Array.isArray(keysOrMapper)
    ? keysOrMapper.reduce((reduced, key) => {
        reduced[key] = {
          get(this: ComponentPublicInstance) {
            return useStore(this.$pinia)[key]
          },
          set(this: ComponentPublicInstance, value) {
            return (useStore(this.$pinia)[key] = value as any)
          },
        }
        return reduced
      }, {} as _MapWritableStateReturn<S>)
    : Object.keys(keysOrMapper).reduce((reduced, key: keyof KeyMapper) => {
        reduced[key] = {
          get(this: ComponentPublicInstance) {
            return useStore(this.$pinia)[keysOrMapper[key]]
          },
          set(this: ComponentPublicInstance, value) {
            return (useStore(this.$pinia)[keysOrMapper[key]] = value as any)
          },
        }
        return reduced
      }, {} as _MapWritableStateObjectReturn<S, KeyMapper>)
}mapWritableState实现过程与mapState相似,只不过mapWritableState返回结果中的value是个对象,对象中有get、set函数,通过设置set函数,用户就可以修改对应的state。
总结
mapStores、mapState、mapActions等辅助函数会在内部通过调用useStore(在useStore调用时会传入this.$pinia,this为组件实例,这也是为什么辅助函数不能用在setup中,因为setup中是无法获取组件实例)获取store,然后在store中获取对应属性。
转载自:https://segmentfault.com/a/1190000042007052




