前言

【pinia源码】系列文章次要剖析pinia的实现原理。该系列文章源码参考pinia v2.0.14

源码地址:https://github.com/vuejs/pinia

官网文档:https://pinia.vuejs.org

本篇文章将剖析mapHelper API的实现。

应用

pinia提供了Vuex中的mapStatemapActions等一些辅助函数。这些函数的定义在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.statestate.getter

mapGettersmapState的别名。

应用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 = mapState

mapState能够承受两个参数:useStore(一个useStore函数)、keysOrMapper(一个key列表,或map对象)。

mapState会返回一个对象,这个对象的key值是通过keysOrMapper取得的。如果传入keysOrMapper是数组,返回对象的key就是keysOrMapper中的元素,key对应的值是个获取store[key]的函数。 如果keysOrMapper是个对象,返回对象的keykeysOrMapper中的keykey对应的值依据keysOrMapper[key]的类型有所区别,如果keysOrMapper[key]function,返回后果中对应key的值是一个返回keysOrMapper[key].call(this, store)的函数,否则key对应的是个返回store[keysOrMapper[key]]的函数。

mapGettersmapState

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是个对象,对象中有getset函数,通过设置set函数,用户就能够批改对应的state

总结

mapStoresmapStatemapActions等辅助函数会在外部通过调用useStore(在useStore调用时会传入this.$piniathis为组件实例,这也是为什么辅助函数不能用在setup中,因为setup中是无奈获取组件实例)获取store,而后在store中获取对应属性。