Skip to content
Advertisement

Is it possible to use Vuex mapActions inside an exported module

Is it possible to call Vuex mapActions from a separate module that’s imported into a component?

I’m trying to standardize a set of functions in a vue.js web app. I’d like to import them into each component and pass some values the to function operate. I’m using vuex to manage state. Currently each component calls these functions each time they’re loaded (identically the same).

I’d like to refactor into this into one module and import it into each component as needed. This code uses mapActions as part of it’s function. Below are the relevant pieces of code: component, module, vuex action

Vue component:

//the imported function call
if (!this.queued){
   timer.updatePage(this.pagination, this.orders);
}

the module code (advance.js):

import { mapActions } from 'vuex';

let currentComp = {
   name: 'purchase',
   date: null,
   start: false
}

const timer = {
   ...mapActions(['currentComponent']),
   updatePage(pagination, order) {
      currentComp.name = 'nextComponent';
      this.currentComponent(currentComp);
   }
}
export default timer;

the vuex code:

//in the actions section:
currentComponent({
        commit
    }, comp) {
        console.log(comp);
        commit('setCurrentComponent', comp);
}

//in the mutations section:
setCurrentComponent: (state, comp) => {
        state.currentComponent = comp.name;
        return state;
    }

when the component runs the imported function i get:

vuex.esm.js?2f62:870 Uncaught TypeError: Cannot read property 'dispatch' of undefined
    at Object.mappedAction [as currentComponent] (vuex.esm.js?2f62:870)
    at eval (advance.js?935c:37)

when i remove the this from this.currentComponent i get:

advance.js?935c:37 Uncaught ReferenceError: currentComponent is not defined
    at eval (advance.js?935c:37)

thanks in advance for any guidance.

Advertisement

Answer

mapActions is a shortcut for creating a method that looks something like this

currentComponent() {
   this.$store.dispatch('xxx')
}

When you call this function, the this context is timer. Since timer does not have a $store property, you get the error Cannot read property 'dispatch' of undefined. The quickest way to get around this would be to change the this context to the component which does have a $store property. You could do this by passing the component as a third property in updatePage and binding currentComponent to the function.

// component code
timer.updatePage(this.pagination, this.orders, this);

// advance.js
const timer = {
   ...mapActions(['currentComponent']),
   updatePage(pagination, order, component) {
      currentComp.name = 'nextComponent';
      this.currentComponent.bind(component)(currentComp);
   }
}

I’d recommend using a mixin for this type of behavior though.

import { mapActions } from 'vuex';

let currentComp = {
   name: 'purchase',
   date: null,
   start: false
}

const timerMixin = {
   methods: {
       ...mapActions(['currentComponent']),
       updatePage(pagination, order) {
          currentComp.name = 'nextComponent';
          this.currentComponent(currentComp);
       }
   }
}
export default timerMixin;

In your component, import the timerMixin and register it as a mixin. Those methods would then be available directly on your component and you can call them with a small tweak to your existing code.

if (!this.queued){
   this.updatePage(this.pagination, this.orders);
}
User contributions licensed under: CC BY-SA
4 People found this is helpful
Advertisement