Change another module state from one module in Vuex

vue.jsVuejs2Vuex

vue.js Problem Overview


I have two modules in my vuex store.

var store = new Vuex.Store({
    modules: {
        loading: loading 
        posts: posts
    }
});

In the module loading, I have a property saving which can be set either true or false and also have a mutation function named TOGGLE_SAVING to set this property.

In the module posts, before and after fetching posts, I want to change the property saving. I am doing it by calling commit('TOGGLE_SAVING') from one of the actions in the posts module.

var getPosts = function (context) {
    context.commit(TOGGLE_LOADING);
};

When it tried to commit, I got following error in the console

[vuex] unknown local mutation type: TOGGLE_LOADING, global type: posts/TOGGLE_LOADING 

How can I mutate state in another module using commit?

vue.js Solutions


Solution 1 - vue.js

Try it with following parameters as suggested here;

commit('TOGGLE_LOADING', null, { root: true })

If you have namespaced set to true (in Nuxt that's the default when in modules mode), this becomes:

commit('loading/TOGGLE_LOADING', null, { root: true })

Solution 2 - vue.js

you can use action to commit mutation which defined in another module,then you will modify state in another module.

like this:

posts: {
  actions: {
    toggleSavingActions(context) {
      // some actions 
      context.commit("TOGGLE_SAVING"); // defined in loading module
    }
  }
}

Solution 3 - vue.js

You can also import the store, as you normally do in any js file and use it. For example:

// src/state/modules/posts.js

import store from '@/state/store'
...
store.commit('posts/TOGGLE_LOADING')
...

This works pretty well, the only donwside is that can difficult isolate tests or mock-up.


Edition: Recently I have eliminated all code using the technique I mention due the testing problems. Indeed you can always change the state of other modules following the recommended way, as in this example. Very useful if you manage auth and profile in distincts modules.

logout: context => {
  return new Promise((resolve) => {
    // Clear token in all axios requests
    axios.defaults.headers.common['Authorization'] = ''
    // Logout from firebase
    firebase
      .auth()
      .signOut()
      .then(() => {
        // Update state in profile module
        context.commit('profile/SET_USER', null, {
          root: true
        })
        resolve()
      })
      .catch(error => reject(error))
  })
}

Solution 4 - vue.js

If you have used namespaced: true in your modules, there are two ways for it:

1- you should add { root: true }:

commit('TOGGLE_LOADING', null, { root: true }) 

2- define a global action as below (e.g. globalToggleLoading) and call it from any modules you want by dispatch('globalToggleLoading')

globalToggleLoading: {
    root: true,
    handler({ commit }) {
      commit('TOGGLE_LOADING')
    }
  }

If your modules are not namespaced, you can call any mutations or actions by calling commit, dispatch:

commit('TOGGLE_LOADING')

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
QuestionFizer KhanView Question on Stackoverflow
Solution 1 - vue.jsSaurabhView Answer on Stackoverflow
Solution 2 - vue.jsJulienView Answer on Stackoverflow
Solution 3 - vue.jsIgor ParraView Answer on Stackoverflow
Solution 4 - vue.jsrebinnafView Answer on Stackoverflow