From: Eduardo San Martin Morote Date: Wed, 7 Apr 2021 14:31:56 +0000 (+0200) Subject: refactor: cache store create per instance X-Git-Tag: v0.3.0~17 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=96c746565bd877762b4008af3e1806aa22fa383a;p=thirdparty%2Fvuejs%2Fpinia.git refactor: cache store create per instance --- diff --git a/src/mapHelpers.ts b/src/mapHelpers.ts index b8ae0a97..42f2b883 100644 --- a/src/mapHelpers.ts +++ b/src/mapHelpers.ts @@ -1,4 +1,6 @@ +import type Vue from 'vue' import { + GenericStore, GenericStoreDefinition, Method, StateTree, @@ -21,8 +23,21 @@ type Spread = A extends [infer L, ...infer R] ? StoreObject & Spread : unknown +function getCachedStore< + Id extends string = string, + S extends StateTree = StateTree, + G = Record, + A = Record +>(vm: Vue, useStore: StoreDefinition): Store { + const cache = vm._pStores || (vm._pStores = {}) + const id = useStore.$id + return (cache[id] || (cache[id] = useStore(vm.$pinia))) as Store +} + /** - * Allows using stores without the composition API (`setup()`) by generating an object to be spread in the `computed` field of a component. + * Allows using stores without the composition API (`setup()`) by generating an + * object to be spread in the `computed` field of a component. it accepts a list + * of store definitions. * * @example * ```js @@ -31,7 +46,7 @@ type Spread = A extends [infer L, ...infer R] * // other computed properties * ...mapStores(useUserStore, useCartStore) * }, - + * * created() { * this.userStore // store with id "user" * this.cartStore // store with id "cart" @@ -41,13 +56,13 @@ type Spread = A extends [infer L, ...infer R] * * @param stores - list of stores to map to an object */ -export function mapStores( +export function mapStores( ...stores: [...Stores] ): Spread { return stores.reduce((reduced, useStore) => { // @ts-ignore: $id is added by defineStore - reduced[useStore.$id + 'Store'] = function () { - return (useStore as GenericStoreDefinition)((this as any).$pinia) + reduced[useStore.$id + 'Store'] = function (this: Vue) { + return getCachedStore(this, useStore) } return reduced }, {} as Spread) @@ -91,15 +106,15 @@ export function mapState< ): MapStateReturn | MapStateObjectReturn { return Array.isArray(keysOrMapper) ? keysOrMapper.reduce((reduced, key) => { - // @ts-ignore: too complicated for TS - reduced[key] = function () { - return useStore((this as any).$pinia)[key] + // @ts-ignore: sorry TS + reduced[key] = function (this: Vue) { + return getCachedStore(this, useStore)[key] } return reduced }, {} as MapStateReturn) : Object.keys(keysOrMapper).reduce((reduced, key: keyof KeyMapper) => { - reduced[key] = function () { - return useStore((this as any).$pinia)[keysOrMapper[key]] + reduced[key] = function (this: Vue) { + return getCachedStore(this, useStore)[keysOrMapper[key]] } return reduced }, {} as MapStateObjectReturn) diff --git a/src/plugin.ts b/src/plugin.ts index 4f62bc9f..a95e7096 100644 --- a/src/plugin.ts +++ b/src/plugin.ts @@ -51,5 +51,9 @@ export const PiniaPlugin: PluginFunction = function (_Vue) { this.$pinia = options.parent.$pinia } }, + destroyed() { + // @ts-ignore: clear up the store cache + delete this._pStores + }, }) } diff --git a/src/rootStore.ts b/src/rootStore.ts index 850edbcb..67b318f4 100644 --- a/src/rootStore.ts +++ b/src/rootStore.ts @@ -4,6 +4,7 @@ import { StoreWithState, StateDescriptor, PiniaCustomProperties, + GenericStore, } from './types' import { VueConstructor } from 'vue' import type Vue from 'vue' @@ -65,12 +66,25 @@ export interface Pinia { declare module 'vue/types/vue' { interface Vue { + /** + * Currently installed pinia instance. + */ $pinia: Pinia + + /** + * Cache of stores instantiated by the current instance. Used by map + * helpers. + */ + _pStores?: Record } } declare module 'vue/types/options' { interface ComponentOptions { + /** + * Pinia instance to install in your application. Should be passed to the + * root Vue. + */ pinia?: Pinia } } @@ -91,7 +105,7 @@ export function createPinia(): Pinia { use(plugin) { /* istanbul ignore next */ - if (__DEV__) { + if (__DEV__ && !__TEST__) { console.warn( `[🍍]: The plugin API has plans to change to bring better extensibility. "pinia.use()" signature will change in the next release. It is recommended to avoid using this API.` ) diff --git a/src/types.ts b/src/types.ts index 736fd945..9ab1fcc7 100644 --- a/src/types.ts +++ b/src/types.ts @@ -112,11 +112,11 @@ export type StoreWithGetters = { // : never // } -// has the actions without the context (this) for typings export type Store< Id extends string, S extends StateTree, G, + // has the actions without the context (this) for typings A > = StoreWithState & S & @@ -138,7 +138,7 @@ export interface StoreDefinition< } /** - * Generic version of Store + * Generic version of Store. */ export type GenericStore = Store< string, @@ -148,17 +148,14 @@ export type GenericStore = Store< > /** - * Generic version of `StoreDefinition` + * Generic version of `StoreDefinition`. */ -export interface GenericStoreDefinition { - (pinia?: Pinia | null | undefined): Store< - string, - StateTree, - Record, - Record - > - $id: string -} +export type GenericStoreDefinition = StoreDefinition< + string, + StateTree, + Record, + Record +> export interface DevtoolHook { on(