+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
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)
+ })
})
markRaw,
inject,
onUnmounted,
+ InjectionKey,
+ provide,
} from '@vue/composition-api'
import {
StateTree,
StoreWithActions,
Method,
StateDescriptor,
- PiniaCustomProperties,
StoreDefinition,
GettersTree,
DefineStoreOptions,
+ GenericStore,
} from './types'
import { useStoreDevtools } from './devtools'
import {
$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)
$reset,
} as StoreWithState<Id, S>
+ const injectionSymbol = __DEV__ ? Symbol(`PiniaStore(${$id})`) : Symbol()
+
return [
storeWithState,
{
isListening = true
},
},
+ injectionSymbol,
]
}
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)
// 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) {
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
+ )
)
}