]> git.ipfire.org Git - thirdparty/vuejs/pinia.git/commitdiff
refactor: cache store create per instance
authorEduardo San Martin Morote <posva13@gmail.com>
Wed, 7 Apr 2021 14:31:56 +0000 (16:31 +0200)
committerEduardo San Martin Morote <posva@users.noreply.github.com>
Fri, 9 Apr 2021 11:08:56 +0000 (13:08 +0200)
src/mapHelpers.ts
src/rootStore.ts
src/types.ts

index b8ae0a97e178b4aad353cb21722584338a9ce672..42f2b883ca7fccffb7153866c81e283eb143a92c 100644 (file)
@@ -1,4 +1,6 @@
+import type Vue from 'vue'
 import {
+  GenericStore,
   GenericStoreDefinition,
   Method,
   StateTree,
@@ -21,8 +23,21 @@ type Spread<A extends readonly any[]> = A extends [infer L, ...infer R]
   ? StoreObject<L> & Spread<R>
   : unknown
 
+function getCachedStore<
+  Id extends string = string,
+  S extends StateTree = StateTree,
+  G = Record<string, Method>,
+  A = Record<string, Method>
+>(vm: Vue, useStore: StoreDefinition<Id, S, G, A>): Store<Id, S, G, A> {
+  const cache = vm._pStores || (vm._pStores = {})
+  const id = useStore.$id
+  return (cache[id] || (cache[id] = useStore(vm.$pinia))) as Store<Id, S, G, A>
+}
+
 /**
- * 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 readonly any[]> = 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 readonly any[]> = A extends [infer L, ...infer R]
  *
  * @param stores - list of stores to map to an object
  */
-export function mapStores<Stores extends unknown[]>(
+export function mapStores<Stores extends GenericStoreDefinition[]>(
   ...stores: [...Stores]
 ): Spread<Stores> {
   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<Stores>)
@@ -91,15 +106,15 @@ export function mapState<
 ): MapStateReturn<S, G> | MapStateObjectReturn<S, G, KeyMapper> {
   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<S, G>)
     : 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<S, G, KeyMapper>)
index 492d755dcba0edf493ac18e4e628b25a16312bc0..eabd2b96b19deeae20442f3a657f2e4a79af4b15 100644 (file)
@@ -5,6 +5,7 @@ import {
   StoreWithState,
   StateDescriptor,
   PiniaCustomProperties,
+  GenericStore,
 } from './types'
 
 /**
@@ -94,6 +95,12 @@ declare module '@vue/runtime-core' {
      * Access to the application's Pinia
      */
     $pinia: Pinia
+
+    /**
+     * Cache of stores instantiated by the current instance. Used by map
+     * helpers.
+     */
+    _pStores?: Record<string, GenericStore>
   }
 }
 
@@ -134,7 +141,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.`
         )
index 1df5055a0c73135d07ef9b8d167832218af959af..14149df5d4648d5425cd4ec39a01c89035baf392 100644 (file)
@@ -136,7 +136,6 @@ export type StoreWithGetters<G> = {
 //     : never
 // }
 
-// has the actions without the context (this) for typings
 /**
  * Store type to build a store
  */
@@ -144,6 +143,7 @@ export type Store<
   Id extends string,
   S extends StateTree,
   G,
+  // has the actions without the context (this) for typings
   A
 > = StoreWithState<Id, S> &
   S &
@@ -165,7 +165,7 @@ export interface StoreDefinition<
 }
 
 /**
- * Generic version of Store
+ * Generic version of Store.
  */
 export type GenericStore = Store<
   string,
@@ -175,17 +175,14 @@ export type GenericStore = Store<
 >
 
 /**
- * Generic version of `StoreDefinition`
+ * Generic version of `StoreDefinition`.
  */
-export interface GenericStoreDefinition {
-  (pinia?: Pinia | null | undefined): Store<
-    string,
-    StateTree,
-    Record<string, Method>,
-    Record<string, Method>
-  >
-  $id: string
-}
+export type GenericStoreDefinition = StoreDefinition<
+  string,
+  StateTree,
+  Record<string, Method>,
+  Record<string, Method>
+>
 
 /**
  * Properties that are added to every store by `pinia.use()`