Search code examples
vue.jsvuex

Access $root instance from vuex actions


I have a Loader component in which it will execute based on

created() {
    this.$root.$on('show-loading', (vars) => {
        this.loading = vars;
        console.log('loader executed');
    });
},

Currently from a vue component i can execute show-loading through this.$root.$emit('show-loading', true);.

However, I am trying to execute the code now from my vuex module file. I get an error of

TypeError: "_this.$root is undefined"

Anyone knows the proper way of accessing the root instance from vuex?


Solution

  • Don't put event handlers in the Vuex store. They do not belong there, and they will never work as expected. In the store you have getters (ways of getting values out of your store), mutations (synchronous setters), actions (asynchronous setters) and the state (your data).

    Listeners belong on a Vue instance, such as a component. Other than that I would also suggest avoiding this.$root and this.$parent like the plague. Having these in your code commonly suggests that you are changing components outside their actual component files, which causes magic behaviour where things change where you do not expect them to change.

    In your case what you want to do can much more easily be done with a single store mutation or action.

    In your store create a mutation

    const mutations = {
      showLoading(state, data) {
        state.loading = data;
      }
    };
    

    Now in your component just use this.$store.commit('showLoading', true);. No event bus needed. No events that magically turn up in the root component. Just a single synchronous setter.


    If you need to have global event handling you can instead use a bus.

    const $bus = new Vue();
    
    Vue.prototype.$bus = $bus;
    

    In components you can listen to events with this.$bus.$on(...) or emit events with this.$bus.$emit(...). If you need to do stuff outside of Vue entirely, you can create event listeners outside of a component using the following pattern.

    $bus.$on('show-loading', (vars) => {
        // Do something
    });
    

    Technically it would allow you to even load the store with import store from '../path/to/store' and store.commit(...).