David Starkey
David Starkey

Reputation: 1840

How to use vuex action in function

I'm new to Vue, so it's likely I misunderstand something. I want to call a vuex action inside a local function in App.vue like so:

<template>
  <div id="app">
    <button @click="runFunction(1)">Test</button>
  </div>
</template>

<script>
import { mapActions } from 'vuex'

export default{
  data() { return { } },
  methods: {
      ...mapActions(['doAction']),
      buttonClicked: (input) => { runFunction(input) }
  }
}

function runFunction(input){
  doAction({ ID: input });
}
</script>

The action calls a mutation in store.js

import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex);

export default new Vuex.Store({
  state: {
    IDs: []
  },
  mutations: {
    doAction: (state, id) => { state.IDs.push(id) }
  },
  actions: {
    doAction: ({ commit }, id) => { commit('doAction', id) }
  }
})

I also have a main.js that sets up the vue:

import Vue from 'vue'
import App from './App.vue'
import store from './store'

new Vue({
  el: '#app',
  store,
  render: h => h(App)
})

The error I'm getting is:

ReferenceError: doAction is not defined
  at runFunction

How can I call the mapped action inside a function? Version is Vue 2.6.10

Upvotes: 1

Views: 3266

Answers (2)

skirtle
skirtle

Reputation: 29132

There are several problems with defining runFunction as a 'local function':

function runFunction(input){
  doAction({ ID: input });
}

Firstly, this is just a normal JavaScript function and the usual scoping rules apply. doAction would need to be defined somewhere that this function can see it. There is no magic link between this function and the component defined in App.vue. The function will be accessible to code in the component, such as in buttonClicked, but not the other way around.

The next problem is that it won't be available within your template. When you write runTemplate(1) in your template that's going to be looking for this.runTemplate(1), trying to resolve it on the current instance. Your function isn't on the current instance. Given your template includes @click="runFunction(1)" I'm a little surprised you aren't seeing a console error warning that the click handler is undefined.

mapActions accesses the store by using the reference held in this.$store. That reference is created when you add the store to your new Vue({store}). The store may appear to be available by magic but it's really just this.$store, where this is the current component.

It isn't really clear why you're trying to write this function outside of the component. The simplest solution is to add it to the methods. It'll then be available to the template and you can access doAction as this.doAction.

To keep it as a separate function you'd need to give it some sort of access to the store. Without knowing why you want it to be separate in the first place it's unclear how best to achieve that.

Upvotes: 1

Abdelillah Aissani
Abdelillah Aissani

Reputation: 3108

Of course it is not defined outside your instance .... you have to import the exported store from store.js on your function component :

<script>
import { mapActions } from 'vuex'

import store from 'store.js'

export default{
  data() { return { } },
  methods: {
      ...mapActions(['doAction']),
      buttonClicked: (input) => { runFunction(input) }
  }
}

function runFunction(input){
  store.commit({ ID: input });
}
</script>

Upvotes: 1

Related Questions