前言
【pinia源码】系列文章主要分析pinia
的实现原理。该系列文章源码参考pinia v2.0.14
。
官方文档:pinia.vuejs.org
本篇文章将分析defineStore
的实现。
使用
通过defineStore
定义一个store
。
const useUserStore = defineStore('counter', {
state: () => ({
count: 0
}),
actions: {
increment() {
this.count++
}
}
})
// or
const useUserStore = defineStore({
id: 'counter',
state: () => ({
count: 0
}),
actions: {
increment() {
this.count++
}
}
})
// or
const useUserStore = defineStore('counter', () => {
const count = ref(0)
function increment() {
count.value++
}
return { count, increment }
})
defineStore
export function defineStore( idOrOptions: any,
setup?: any,
setupOptions?: any ): StoreDefinition {
let id: string
let options:
| DefineStoreOptions<
string,
StateTree,
_GettersTree<StateTree>,
_ActionsTree
>
| DefineSetupStoreOptions<
string,
StateTree,
_GettersTree<StateTree>,
_ActionsTree
>
const isSetupStore = typeof setup === 'function'
if (typeof idOrOptions === 'string') {
id = idOrOptions
options = isSetupStore ? setupOptions : setup
} else {
options = idOrOptions
id = idOrOptions.id
}
function useStore(pinia?: Pinia | null, hot?: StoreGeneric): StoreGeneric { // ... }
useStore.$id = id
return useStore
}
defineStore
函数可以接收三个参数:idOrOptions
、setup
、setOptions
,后两个参数为可选参数。下面是三个defineStore
的函数类型定义。
export function defineStore<
Id extends string,
S extends StateTree = {},
G extends _GettersTree<S> = {},
A /* extends ActionsTree */ = {}
>(
id: Id,
options: Omit<DefineStoreOptions<Id, S, G, A>, 'id'>
): StoreDefinition<Id, S, G, A>
export function defineStore<
Id extends string,
S extends StateTree = {},
G extends _GettersTree<S> = {},
A /* extends ActionsTree */ = {}
>(options: DefineStoreOptions<Id, S, G, A>): StoreDefinition<Id, S, G, A>
export function defineStore<Id extends string, SS>( id: Id,
storeSetup: () => SS,
options?: DefineSetupStoreOptions<
Id,
_ExtractStateFromSetupStore<SS>,
_ExtractGettersFromSetupStore<SS>,
_ExtractActionsFromSetupStore<SS>
> ): StoreDefinition<
Id,
_ExtractStateFromSetupStore<SS>,
_ExtractGettersFromSetupStore<SS>,
_ExtractActionsFromSetupStore<SS>
>
首先在defineStore
中声明了三个变量:id
、options
、isSetupStore
,其中id
为定义的store
的唯一id
,options
为定义store
时的options
,isSetupStore
代表传入的setup
是不是个函数。
然后根据传入的idOrOptions
的类型,为id
、otions
赋值。紧接着声明了一个useStore
函数,并将id
赋给它,然后将其return
。截止到此,我们知道defineStore
会返回一个函数,那么这个函数具体是做什么的呢?我们继续看useStore
的实现。
useStore
function useStore(pinia?: Pinia | null, hot?: StoreGeneric): StoreGeneric {
// 获取当前实例
const currentInstance = getCurrentInstance()
// 测试环境下,忽略提供的参数,因为总是能使用getActivePinia()获取pinia实例
// 非测试环境下,如果未传入pinia,则会从组件中使用inject获取pinia
pinia =
(__TEST__ && activePinia && activePinia._testing ? null : pinia) ||
(currentInstance && inject(piniaSymbol))
// 设置激活的pinia
if (pinia) setActivePinia(pinia)
// 如果没有activePinia,那么可能没有install pinia,开发环境下进行提示
if (__DEV__ && !activePinia) {
throw new Error(
`[🍍]: getActivePinia was called with no active Pinia. Did you forget to install pinia?\n` +
`\tconst pinia = createPinia()\n` +
`\tapp.use(pinia)\n` +
`This will fail in production.`
)
}
// 设置pinia为激活的pinia
pinia = activePinia!
// 从pina._s中查找id否注册过,如果没有被注册,创建一个store并注册在pinia._s中
if (!pinia._s.has(id)) {
if (isSetupStore) {
createSetupStore(id, setup, options, pinia)
} else {
createOptionsStore(id, options as any, pinia)
}
if (__DEV__) {
useStore._pinia = pinia
}
}
// 从pinia._s中获取id对应的store
const store: StoreGeneric = pinia._s.get(id)!
if (__DEV__ && hot) {
const hotId = '__hot:' + id
const newStore = isSetupStore
? createSetupStore(hotId, setup, options, pinia, true)
: createOptionsStore(hotId, assign({}, options) as any, pinia, true)
hot._hotUpdate(newStore)
// cleanup the state properties and the store from the cache
delete pinia.state.value[hotId]
pinia._s.delete(hotId)
}
if (
__DEV__ &&
IS_CLIENT &&
currentInstance &&
currentInstance.proxy &&
!hot
) {
const vm = currentInstance.proxy
const cache = '_pStores' in vm ? vm._pStores! : (vm._pStores = {})
cache[id] = store
}
// 返回store
return store as any
}
useStore
接收两个可选参数:pinia