vuex-class-modules icon indicating copy to clipboard operation
vuex-class-modules copied to clipboard

wrapped Action (accessing context)

Open mrmoses opened this issue 4 years ago • 4 comments

Is it possible to define an Action that gets wrapped in another function?

Example of wrapping an action using vuexfire:

actions: {
    bindTodos: firestoreAction(({ bindFirestoreRef }) => {
      // return the promise returned by `bindFirestoreRef`
      return bindFirestoreRef('todos', db.collection('todos'))
    }),
  }

I've tried a few different ways.

@Action
bindTodos1 = firestoreAction(({ bindFirestoreRef }) => {
  // return the promise returned by `bindFirestoreRef`
  return bindFirestoreRef('todos', db.collection('todos'))
})
// ^ Unable to resolve signature of property decorator when called as an expression. ts(1240)

@Action 
bindTodos2 () {
  return firestoreAction(({ bindFirestoreRef }) => {
    return bindFirestoreRef('todos', db.collection('todos'))
  })
}
// ^ compiles, and seems to execute, but does not update 'todos' state property 

bindTodos3 = firestoreAction(({ bindFirestoreRef }) => {
  return bindFirestoreRef('todos', db.collection('todos'))
})

@Action 
bindTodos4 () {
  return this.bindTodos3()
}

Is there a specific syntax or even a workaround to get a firestoreAction into a VuexModule ?

mrmoses avatar Feb 22 '20 20:02 mrmoses

You could define your own decorator for it:

function FirestoreAction(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    descriptor.value = firestoreAction(descriptor.value);
    return descriptor;
}

Then use it as:

@Action
@FirestoreAction
bindTodos({ bindFirestoreRef }) {
    return bindFirestoreRef('todos', db.collection('todos'));
}

At least I think that should work. Haven’t tried it myself.

bodograumann avatar Feb 22 '20 21:02 bodograumann

Thanks @bodograumann that helps.

bindFirestoreRef is something that is injected into the context by firestoreAction, so its not a parameter to mymodule.bindTodos()

In regular actions, the first param is the context:

actions: {
  bindTodos({ commit, state }) {
    // ...
  }
}

How can that context be accessed inside either the FirestoreAction decorator or in the bindTodos action?

Here is a FirestoreAction decorator that uses firestoreAction to create the action, and then calls it (from here)

export function FirestoreAction() {
  return function(_target: any, _key: string, descriptor: PropertyDescriptor) {
    const delegate: Function = descriptor.value
    descriptor.value = function(payload: any) {
      const action = firestoreAction((context) => {
        const thisObj = { context }
        return delegate.call(thisObj, payload)
      }) as Function
      // @ts-ignore
      return action(this.context)
    }
  }
}

But this.context is undefined.

mrmoses avatar Feb 23 '20 00:02 mrmoses

Here is an action without the decorator which might work if the context was available (this.context) in the action.

  @Action
  bindTodos () {
    return (firestoreAction(({ bindFirestoreRef }) => {
      return bindFirestoreRef('bindTodos', firestore.collection('bindTodos'))
    }) as Function)(this.context)
  }

Is there anyway to get the context?

mrmoses avatar Feb 23 '20 05:02 mrmoses

The context in vanilla vuex corresponds to this when using vuex-class-modules. It is a proxy which allows you to access the properties which are valid in the current context. So for actions you can directly access state, mutations and other actions.

I don’t think you can simply use this instead of context for firestoreAction though, because vuexfire relies heavily on vanilla vuex api. Not sure how to combine vuexfire and vuex-class-modules. vuex-class-modules’ purpose is to hide the internal vuex api and only expose a class interface, while vuexfire is in its essence using all the technical details of the vanilla vuex api.

bodograumann avatar Feb 23 '20 08:02 bodograumann