前言
【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.`
)
// 開發(fā)環(huán)境下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
會對參數進行校驗,如果傳入的第一個參數為數組噪舀,那么在開發(fā)環(huán)境下會進行提示魁淳,并將數組中的第一個值賦給stores
,以保證開發(fā)環(huán)境下能夠運行与倡。然后返回一個對象界逛,該對象通過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]
的類型有所區(qū)別羽莺,如果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
中獲取對應屬性良姆。