Accessing getters within Vuex mutations

vue.jsVuejs2Vuex

vue.js Problem Overview


Within a Vuex store mutation, is it possible to access a getter? Consider the below example.

new Vuex.Store({
    state: {
        question: 'Is it possible to access getters within a Vuex mutation?'
    },
    mutations: {
        askQuestion(state) {
            // TODO: Get question from getter here
            let question = '';
            
            if (question) {
            	// ...
            }
        }
    },
    getters: {
        getQuestion: (state) => {
            return state.question;
        }
    }
});

Of course the example doesn't make much sense, because I could just access the question property directly on the state object within the mutation, but I hope you see what I am trying to do. That is, conditionally manipulating state.

Within the mutation, this is undefined and the state parameter gives access to the state object, and not the rest of the store.

The documentation on mutations doesn't mention anything about doing this.

My guess would be that it's not possible, unless I missed something? I guess the alternative would be to either perform this logic outside of the store (resulting in code duplication) or implementing an action that does this, because actions have access to the entire store context. I'm pretty sure that it's a better approach, that is to keep the mutation focused on what it's actually supposed to do; mutate the state. That's probably what I'll end up doing, but I'm just curious if accessing a getter within a mutation is even possible?

vue.js Solutions


Solution 1 - vue.js

Vuex store mutation methods do not provide direct access to getters.

This is probably bad practice*, but you could pass a reference to getters when committing a mutation like so:

actions: {
  fooAction({commit, getters}, data) {
    commit('FOO_MUTATION', {data, getters})
  }
},
mutations: {
  FOO_MUTATION(state, {data, getters}) {
    console.log(getters);
  }
}

* It is best practice to keep mutations a simple as possible, only directly affecting the Vuex state. This makes it easier to reason about state changes without having to think about any side effects. Now, if you follow best practices for vuex getters, they should not have any side effects in the first place. But, any logic that needs to reference getters can run in an action, which has read access to getters and state. Then the output of that logic can be passed to the mutation. So, you can pass the reference to the getters object to the mutation, but there's no need to and it muddies the waters.

Solution 2 - vue.js

If you put your getters and mutations in separate modules you can import the getters in the mutations and then do this:

import getters from './getters'

askQuestion(state) {
  const question = getters.getQuestion(state)
  // etc
}

Solution 3 - vue.js

If anyone is looking for a simple solution, @bbugh wrote out a way to work around this here by just having both the mutations and getters use the same function:

function is_product_in_cart (state, product) {
  return state.cart.products.indexOf(product) > -1
}

export default {
  mutations: {
    add_product_to_cart: function (state, product) {
      if (is_product_in_cart(state, product)) {
        return
      }
      state.cart.products.push(product)
    }
  },

  getters: {
    is_product_in_cart: (state) => (product) => is_product_in_cart(state, product)
  }
}

Solution 4 - vue.js

You also can reference the Store object within a mutation, if you declare the store as an expression, like this:

const Store = new Vuex.Store({
  state: {...},
  getters: {...},
  mutations: {
    myMutation(state, payload) {
      //use the getter
      Store.getters.getter
    }
  }
});

Solution 5 - vue.js

Another solution is to import the existing store. Assuming you're using modules and your module is called foo, your mutator file would look like this store/foo/mutations.js:

import index from '../index'
export const askQuestion = (state, obj) => {
    let store = index()
    let getQuestion = store.getters['foo/getQuestion']
}

I'm not saying this is best practise but it seems to work.

Solution 6 - vue.js

Tested with vuex 4

const state = () => ({
  some_state: 1
})

const getters = {
  some_getter: state => state.some_state + 1
}

const mutations = {
  GET_GETTER(state){
    return getters.some_getter(state)
  }
}

Somewhere in you component

store.commit('GET_GETTER') // output: 2

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionba0708View Question on Stackoverflow
Solution 1 - vue.jsthanksdView Answer on Stackoverflow
Solution 2 - vue.jsKees de KooterView Answer on Stackoverflow
Solution 3 - vue.jsdyslexitView Answer on Stackoverflow
Solution 4 - vue.jsLautaro RamosView Answer on Stackoverflow
Solution 5 - vue.jsgeoidesicView Answer on Stackoverflow
Solution 6 - vue.jsAlexandrView Answer on Stackoverflow