From: Eduardo San Martin Morote Date: Mon, 3 May 2021 09:41:33 +0000 (+0200) Subject: perf(store): reuse stores from parent to children components X-Git-Tag: v0.4.0~6 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=fcfda419efb1e40d68f8c75a6f441da453b9207b;p=thirdparty%2Fvuejs%2Fpinia.git perf(store): reuse stores from parent to children components --- diff --git a/__tests__/store.spec.ts b/__tests__/store.spec.ts index f0e99b90..322ebdba 100644 --- a/__tests__/store.spec.ts +++ b/__tests__/store.spec.ts @@ -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 @@ -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: `

child

`, + }) + + mount( + defineComponent({ + setup() { + s1 = useStore() + return { s1 } + }, + components: { Child }, + template: ``, + }), + { localVue, pinia } + ) + + expect(s1).toBeDefined() + expect(s1).toBe(s2) + }) }) diff --git a/src/rootStore.ts b/src/rootStore.ts index 8bd294c1..11127d88 100644 --- a/src/rootStore.ts +++ b/src/rootStore.ts @@ -21,7 +21,14 @@ import type Vue from 'vue' export const storesMap = new WeakMap< Pinia, - Map, StateDescriptor]> + Map< + string, + [ + StoreWithState, + StateDescriptor, + InjectionKey + ] + > >() export const piniaSymbol = (__DEV__ diff --git a/src/store.ts b/src/store.ts index d991aae5..3c877896 100644 --- a/src/store.ts +++ b/src/store.ts @@ -7,6 +7,8 @@ import { markRaw, inject, onUnmounted, + InjectionKey, + provide, } from '@vue/composition-api' import { StateTree, @@ -19,10 +21,10 @@ import { StoreWithActions, Method, StateDescriptor, - PiniaCustomProperties, StoreDefinition, GettersTree, DefineStoreOptions, + GenericStore, } from './types' import { useStoreDevtools } from './devtools' import { @@ -92,7 +94,11 @@ function initStore( $id: Id, buildState: () => S = () => ({} as S), initialState?: S | undefined -): [StoreWithState, { get: () => S; set: (newValue: S) => void }] { +): [ + StoreWithState, + { get: () => S; set: (newValue: S) => void }, + InjectionKey +] { const pinia = getActivePinia() pinia.Vue.set(pinia.state.value, $id, initialState || buildState()) // const state: Ref = toRef(_p.state.value, $id) @@ -174,6 +180,8 @@ function initStore( $reset, } as StoreWithState + const injectionSymbol = __DEV__ ? Symbol(`PiniaStore(${$id})`) : Symbol() + return [ storeWithState, { @@ -184,6 +192,7 @@ function initStore( isListening = true }, }, + injectionSymbol, ] } @@ -273,9 +282,11 @@ export function defineStore< const { id, state, getters, actions } = options function useStore(pinia?: Pinia | null): Store { - // 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) @@ -286,7 +297,11 @@ export function defineStore< // let store = stores.get(id) as Store let storeAndDescriptor = stores.get(id) as - | [StoreWithState, StateDescriptor] + | [ + StoreWithState, + StateDescriptor, + InjectionKey> + ] | undefined if (!storeAndDescriptor) { @@ -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 | undefined, - actions as Record | 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 | undefined, + actions as Record | undefined, + // @ts-expect-error: because of the extend on Actions + options + ) ) }