Skip to content

Commit

Permalink
perf(store): reuse stores from parent to children components
Browse files Browse the repository at this point in the history
  • Loading branch information
posva committed May 3, 2021
1 parent 22c38f4 commit fcfda41
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 15 deletions.
41 changes: 40 additions & 1 deletion __tests__/store.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
import { defineComponent } from '@vue/composition-api'
import { createLocalVue, mount } from '@vue/test-utils'
import Vue from 'vue'
import { createPinia, defineStore, Pinia, setActivePinia } from '../src'
import {
createPinia,
defineStore,
Pinia,
PiniaPlugin,
setActivePinia,
} from '../src'

describe('Store', () => {
let pinia: Pinia
Expand Down Expand Up @@ -154,4 +162,35 @@ describe('Store', () => {
store.$state
)
})

it('reuses stores from parent components', () => {
let s1, s2
const useStore = defineStore({ id: 'one' })
const pinia = createPinia()
pinia.Vue = Vue
const localVue = createLocalVue()
localVue.use(PiniaPlugin)

const Child = defineComponent({
setup() {
s2 = useStore()
},
template: `<p>child</p>`,
})

mount(
defineComponent({
setup() {
s1 = useStore()
return { s1 }
},
components: { Child },
template: `<child/>`,
}),
{ localVue, pinia }
)

expect(s1).toBeDefined()
expect(s1).toBe(s2)
})
})
9 changes: 8 additions & 1 deletion src/rootStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,14 @@ import type Vue from 'vue'

export const storesMap = new WeakMap<
Pinia,
Map<string, [StoreWithState<string, StateTree>, StateDescriptor<StateTree>]>
Map<
string,
[
StoreWithState<string, StateTree>,
StateDescriptor<StateTree>,
InjectionKey<GenericStore>
]
>
>()

export const piniaSymbol = (__DEV__
Expand Down
50 changes: 37 additions & 13 deletions src/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import {
markRaw,
inject,
onUnmounted,
InjectionKey,
provide,
} from '@vue/composition-api'
import {
StateTree,
Expand All @@ -19,10 +21,10 @@ import {
StoreWithActions,
Method,
StateDescriptor,
PiniaCustomProperties,
StoreDefinition,
GettersTree,
DefineStoreOptions,
GenericStore,
} from './types'
import { useStoreDevtools } from './devtools'
import {
Expand Down Expand Up @@ -92,7 +94,11 @@ function initStore<Id extends string, S extends StateTree>(
$id: Id,
buildState: () => S = () => ({} as S),
initialState?: S | undefined
): [StoreWithState<Id, S>, { get: () => S; set: (newValue: S) => void }] {
): [
StoreWithState<Id, S>,
{ get: () => S; set: (newValue: S) => void },
InjectionKey<GenericStore>
] {
const pinia = getActivePinia()
pinia.Vue.set(pinia.state.value, $id, initialState || buildState())
// const state: Ref<S> = toRef(_p.state.value, $id)
Expand Down Expand Up @@ -174,6 +180,8 @@ function initStore<Id extends string, S extends StateTree>(
$reset,
} as StoreWithState<Id, S>

const injectionSymbol = __DEV__ ? Symbol(`PiniaStore(${$id})`) : Symbol()

return [
storeWithState,
{
Expand All @@ -184,6 +192,7 @@ function initStore<Id extends string, S extends StateTree>(
isListening = true
},
},
injectionSymbol,
]
}

Expand Down Expand Up @@ -273,9 +282,11 @@ export function defineStore<
const { id, state, getters, actions } = options

function useStore(pinia?: Pinia | null): Store<Id, S, G, A> {
// const vm = getCurrentInstance()
const hasInstance = getCurrentInstance()
// only run provide when pinia hasn't been manually passed
const shouldProvide = hasInstance && !pinia
// pinia = pinia || (vm && ((vm as any).$pinia as Pinia))
pinia = pinia || (getCurrentInstance() && inject(piniaSymbol))
pinia = pinia || (hasInstance && inject(piniaSymbol))

if (pinia) setActivePinia(pinia)

Expand All @@ -286,7 +297,11 @@ export function defineStore<

// let store = stores.get(id) as Store<Id, S, G, A>
let storeAndDescriptor = stores.get(id) as
| [StoreWithState<Id, S>, StateDescriptor<S>]
| [
StoreWithState<Id, S>,
StateDescriptor<S>,
InjectionKey<Store<Id, S, G, A>>
]
| undefined

if (!storeAndDescriptor) {
Expand All @@ -308,17 +323,26 @@ export function defineStore<
options
)

// allow children to reuse this store instance to avoid creating a new
// store for each child
if (shouldProvide) {
provide(storeAndDescriptor[2], store)
}

return store
}

return buildStoreToUse(
storeAndDescriptor[0],
storeAndDescriptor[1],
id,
getters as GettersTree<S> | undefined,
actions as Record<string, Method> | undefined,
// @ts-expect-error: because of the extend on Actions
options
return (
(hasInstance && inject(storeAndDescriptor[2], null)) ||
buildStoreToUse(
storeAndDescriptor[0],
storeAndDescriptor[1],
id,
getters as GettersTree<S> | undefined,
actions as Record<string, Method> | undefined,
// @ts-expect-error: because of the extend on Actions
options
)
)
}

Expand Down

0 comments on commit fcfda41

Please sign in to comment.