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); }