]> git.ipfire.org Git - thirdparty/vuejs/pinia.git/commitdiff
feat: add mapActions
authorEduardo San Martin Morote <posva13@gmail.com>
Thu, 8 Apr 2021 09:02:03 +0000 (11:02 +0200)
committerEduardo San Martin Morote <posva@users.noreply.github.com>
Fri, 9 Apr 2021 11:08:56 +0000 (13:08 +0200)
__tests__/mapHelpers.spec.ts
src/index.ts
src/mapHelpers.ts

index 1869554aafc4327fd02271db25b27982cc208f80..d256c84c4f55bfa5684b07256c870d7b1ac4bbd7 100644 (file)
@@ -1,6 +1,7 @@
 import {
   createPinia,
   defineStore,
+  mapActions,
   mapGetters,
   mapState,
   mapStores,
@@ -151,4 +152,49 @@ describe('Map Helpers', () => {
       )
     })
   })
+
+  describe('mapActions', () => {
+    const useStore = defineStore({
+      id: 'main',
+      state: () => ({ n: 0 }),
+      actions: {
+        increment() {
+          this.n++
+        },
+        setN(newN: number) {
+          return (this.n = newN)
+        },
+      },
+    })
+
+    it('array', () => {
+      const pinia = createPinia()
+      const Component = defineComponent({
+        template: `<p></p>`,
+        methods: {
+          ...mapActions(useStore, ['increment', 'setN']),
+        },
+      })
+
+      const wrapper = mount(Component, { localVue, pinia })
+
+      expect(wrapper.vm.increment()).toBe(undefined)
+      expect(wrapper.vm.setN(4)).toBe(4)
+    })
+
+    it('object', () => {
+      const pinia = createPinia()
+      const Component = defineComponent({
+        template: `<p></p>`,
+        methods: {
+          ...mapActions(useStore, { inc: 'increment', set: 'setN' }),
+        },
+      })
+
+      const wrapper = mount(Component, { localVue, pinia })
+
+      expect(wrapper.vm.inc()).toBe(undefined)
+      expect(wrapper.vm.set(4)).toBe(4)
+    })
+  })
 })
index fded0df0408b856d88f999274e458f0c23d161ca..7b1caf32a819281e210a763124c6ec626549a660 100644 (file)
@@ -15,6 +15,6 @@ export {
   DefineStoreOptions,
 } from './types'
 
-export { mapStores, mapState, mapGetters } from './mapHelpers'
+export { mapActions, mapStores, mapState, mapGetters } from './mapHelpers'
 // TODO: remove in beta
 export { createStore } from './deprecated'
index 42f2b883ca7fccffb7153866c81e283eb143a92c..e82637e564dada44a2ea58f8d113cc8f70c3ac18 100644 (file)
@@ -124,3 +124,106 @@ export function mapState<
  * Alias for `mapState()`. You should use `mapState()` instead.
  */
 export const mapGetters = mapState
+
+type MapActionsReturn<A> = {
+  [key in keyof A]: Store<string, StateTree, {}, A>[key]
+}
+
+type MapActionsObjectReturn<A, T extends Record<string, keyof A>> = {
+  [key in keyof T]: Store<string, StateTree, {}, A>[T[key]]
+}
+
+/**
+ * Allows directly using actions from your store without using the composition
+ * API (`setup()`) by generating an object to be spread in the `methods` field
+ * of a component.
+ *
+ * @example
+ * ```js
+ * export default {
+ *   methods: {
+ *     // other methods properties
+ *     ...mapActions(useCounterStore, ['increment', 'setCount'])
+ *   },
+ *
+ *   created() {
+ *     this.increment()
+ *     this.setCount(2) // pass arguments as usual
+ *   }
+ * }
+ * ```
+ *
+ * @param useStore - store to map from
+ * @param keys - array of action names to map
+ */
+export function mapActions<Id extends string, S extends StateTree, G, A>(
+  useStore: StoreDefinition<Id, S, G, A>,
+  keys: Array<keyof A>
+): MapActionsReturn<A>
+/**
+ * Allows directly using actions from your store without using the composition
+ * API (`setup()`) by generating an object to be spread in the `methods` field
+ * of a component. The values of the object are the actions while the keys are
+ * the names of the resulting methods.
+ *
+ * @example
+ * ```js
+ * export default {
+ *   methods: {
+ *     // other methods properties
+ *     // useCounterStore has two actions named `increment` and `setCount`
+ *     ...mapActions(useCounterStore, { moar: 'increment', setIt: 'setCount' })
+ *   },
+ *
+ *   created() {
+ *     this.moar()
+ *     this.setIt(2)
+ *   }
+ * }
+ * ```
+ *
+ * @param useStore - store to map from
+ * @param keyMapper - object to define new names for the actions
+ */
+export function mapActions<
+  Id extends string,
+  S extends StateTree,
+  G,
+  A,
+  KeyMapper extends Record<string, keyof A>
+>(
+  useStore: StoreDefinition<Id, S, G, A>,
+  keyMapper: KeyMapper
+): MapActionsObjectReturn<A, KeyMapper>
+/**
+ * Allows directly using actions from your store without using the composition
+ * API (`setup()`) by generating an object to be spread in the `methods` field
+ * of a component.
+ *
+ * @param useStore - store to map from
+ * @param keysOrMapper - array or object
+ */
+export function mapActions<
+  Id extends string,
+  S extends StateTree,
+  G,
+  A,
+  KeyMapper extends Record<string, keyof A>
+>(
+  useStore: StoreDefinition<Id, S, G, A>,
+  keysOrMapper: Array<keyof A> | KeyMapper
+): MapActionsReturn<A> | MapActionsObjectReturn<A, KeyMapper> {
+  return Array.isArray(keysOrMapper)
+    ? keysOrMapper.reduce((reduced, key) => {
+        reduced[key] = function (this: Vue, ...args: any[]) {
+          return (getCachedStore(this, useStore)[key] as Method)(...args)
+        } as Store<string, StateTree, {}, A>[keyof A]
+        return reduced
+      }, {} as MapActionsReturn<A>)
+    : Object.keys(keysOrMapper).reduce((reduced, key: keyof KeyMapper) => {
+        reduced[key] = function (this: Vue, ...args: any[]) {
+          return getCachedStore(this, useStore)[keysOrMapper[key]](...args)
+        } as Store<string, StateTree, {}, A>[keyof KeyMapper[]]
+        return reduced
+      }, {} as MapActionsObjectReturn<A, KeyMapper>)
+}