前言
【pinia源码】系列文章次要剖析pinia
的实现原理。该系列文章源码参考pinia v2.0.14
。
源码地址:https://github.com/vuejs/pinia
官网文档:https://pinia.vuejs.org
本篇文章将剖析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 = mapState
mapState
能够承受两个参数: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
中获取对应属性。