Skip to content

vuex-module-decorators Integration #90

@No3x

Description

@No3x

Is there a way to integrate this with vuex-module-decorators? mapWaitingActions won't work here since the action ist mapped in by @Action.

Example taken from https://blog.logrocket.com/how-to-write-a-vue-js-app-completely-in-typescript/ but with modifications to make it work:

npm install vuex-module-decorators -D
npm install vuex-class -D
// store/modules/user.ts
import { VuexModule, Module, Mutation, Action } from 'vuex-module-decorators'
import store from "@/store";

interface IUserState {
  name: string
}

@Module({ store: store, namespaced: true })
export default class User extends VuexModule implements IUserState {
  public name: string = ''
  @Mutation
  public setName(newName: string): void {
    this.name = newName
  }

  get nameUpperCase() {
    return this.name.toUpperCase();
  }

  @Action
  public updateName(newName: string): void {
    this.context.commit('setName', newName)
  }
}
export default User
// store.ts
import Vue from 'vue'
import Vuex from 'vuex'
import User from '@/store/modules/user'
Vue.use(Vuex)
const store = new Vuex.Store({
  modules: {
    user: User
  }
})
export default store
<!-- User.vue -->
<template>
  <div class="details">
    <div class="username">User: {{ nameUpperCase }}</div>
    <input :value="name" @keyup="updateName($event.target.value)" />
  </div>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'
import { namespace } from 'vuex-class'
const user = namespace('user')
@Component
export default class User extends Vue {
  @user.State
  public name!: string

  @user.Getter
  public nameUpperCase!: string

  @user.Action
  public updateName!: (newName: string) => void
}
</script>

And a variant of the similar @MutateAction:

// store/modules/user.ts
import {
  Module, Mutation, MutationAction,
  VuexModule, Action,
} from 'vuex-module-decorators';
import { Veterinarian, VeterinarianControllerApi, VeterinarianSpecialisationEnum } from '@/services';
import { Getter } from 'vuex-class';
import store from '@/store';

interface IUserState {
  name: string
}

@Module({ store, namespaced: true })
export default class User extends VuexModule implements IUserState {
  public name: string = 'defaultValue'

  get nameUpperCase() {
    return this.name.toUpperCase();
  }

  @MutationAction({ mutate: ['name'] })
  async updateName(newName: string) {
    return { name: newName };
  }
}

Wrapping the invocation of the Actions would be nice to trigger the wait start and end.

What I tried:
I created my own WaitingMutationAction decorator. I just took the original one and wrapped the action with start and end:

WaitingMutationAction
 export interface MutationActionParams<M> {
   mutate?: (keyof Partial<M>)[]
   rawError?: boolean
   root?: boolean
 }
 
-function mutationActionDecoratorFactory<T extends Object>(params: MutationActionParams<T>) {
+function waitingMutationActionDecoratorFactory<T extends Object>(params: MutationActionParams<T>) {
   return function(
     target: T,
     key: string | symbol,
     descriptor: TypedPropertyDescriptor<(...args: any[]) => Promise<Partial<T>>>
   ) {
     const module = target.constructor as Mod<T, any>
 
     const action: Act<typeof target, any> = async function(
       context: ActionContext<typeof target, any>,
       payload: Payload
     ) {
       try {
+        this._vm.$wait.start("test");
         const actionPayload = await mutactFunction.call(context, payload)
         context.commit(key as string, actionPayload)
       } catch (e) {
         if (params.rawError) {
           throw e
         } else {
           console.error('Could not perform action ' + key.toString())
           console.error(e)
           return Promise.reject(e)
         }
+      } finally {
+        this._vm.$wait.end("test");
       }
     }
 
     const mutation: Mut<typeof target> = function(
       state: typeof target | Store<T>,
       payload: Payload & { [k in keyof T]: any }
     }
     module.actions![key as string] = params.root ? { root: true, handler: action } : action
     module.mutations![key as string] = mutation
   }
 }
 
-export function MutationAction<K, T extends K>(
+export function WaitingMutationAction<K, T extends K>(
   target: { [k in keyof T]: T[k] | null },
   key: string | symbol,
   descriptor: TypedPropertyDescriptor<(...args: any[]) => Promise<K>>
 ): void
 
-export function MutationAction<T>(
+export function WaitingMutationAction<T>(
   params: MutationActionParams<T>
 ): (
   target: T,
   key: string | symbol,
   descriptor: TypedPropertyDescriptor<(...args: any[]) => Promise<T>>
 ) => void
  *
  * @param paramsOrTarget the params or the target class
  * @param key the name of the function
  * @param descriptor the function body
  * @constructor
  */
-export function MutationAction<T, K, M extends K>(
+export function WaitingMutationAction<T, K, M extends K>(
   paramsOrTarget: MutationActionParams<T> | M,
   key?: string | symbol,
   descriptor?: TypedPropertyDescriptor<(...args: any[]) => Promise<Partial<K>>>
 ):
   | ((
       target: T,
         @MutationAction({mutate: ['incrCount']})
         async getCountDelta() {
           return {incrCount: 5}
         }
      * </pre>
      */
-    return mutationActionDecoratorFactory(paramsOrTarget as MutationActionParams<T>)
+    return waitingMutationActionDecoratorFactory(paramsOrTarget as MutationActionParams<T>)
   } else {
     /*
      * This is the case when `paramsOrTarget` is target.
      * i.e. when used as -
      * <pre>
         @MutationAction
         async getCountDelta() {
           return {incrCount: 5}
         }
      * </pre>
      */
-    mutationActionDecoratorFactory({} as MutationActionParams<K>)(
+    waitingMutationActionDecoratorFactory({} as MutationActionParams<K>)(
       paramsOrTarget as K,
       key!,
       descriptor!
     )
   }
 }
Well, it works. But it's too much code duplication and dumb.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions