Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can a Vuex module watch another Vuex module?

Can Vuex modules watch the state of other modules, and trigger actions consequently?

For example, let's consider the following case:

store.js

import time from './store/time' ;
import position from './store/position' ;

const store = new Vuex.Store
(
    {
        modules:
        {
            time,
            position
        }    
    }
) ;

store/time.js

export default
{

    namespaced: true,

    state:
    {
        time: new Date()
    },

    getters:
    {
        time: (aState) => aState.time
    },

    mutations:
    {

        setTime (aState, aTime)
        {
            aState.time = aTime ;
        }

    }

} ;

store/position.js

export default
{

    namespaced: true,

    state:
    {
        positions: {}
    },

    getters:
    {
        positions: aState => aState.positions
    },

    mutations:
    {

        setPositions (aState, aPositionArray)
        {
            aState.positions = aPositionArray ;
        }

    },

    actions:
    {

        fetchPositionsAtTime ({ dispatch, commit, rootGetters }, { time })
        {
            // Fetch positions at given time from the server
            // commit('setPositions', ...)
        }

    }

} ;

Ideally, I would like the position module to watch the time module, and re-fetch the positions (i.e. trigger fetchPositionsAtTime) as soon as the time state changes.

Of course, I could add a dispatch to the setTime mutation to trigger a position module action, but I believe going the other way around (i.e. watching) would be more elegant (as many more modules may require time).

Any solution to this? (without using Vue Component of course, that is the whole point)

like image 813
Lucas Avatar asked Apr 20 '18 17:04

Lucas


People also ask

How would you commit a mutation from another module Vuex?

To change another module state from one module in Vuex, we can call commit with the mutation name with the root option set to true . commit("TOGGLE_LOADING", null, { root: true }); to call commit to commit the TOGGLE_LOADING mutation with root set to true .

Does Vuex work across tabs?

This Vuex plugin allows you to sync and share the status of your Vue application across multiple tabs or windows using the local storage.

Is Vuex asynchronous?

Note we are performing a flow of asynchronous operations, and recording the side effects (state mutations) of the action by committing them.

What is Namespaced in Vuex?

In the previous Vuex tutorial, we learned that by default, getters, actions, and mutations inside modules are registered under the global namespace, which allows multiple modules to react to the same mutation or action.


Video Answer


1 Answers

You can use the store instance's watch method to watch the time state and then dispatch the fetchPositionsAtTime action whenever that time value changes:

store.watch((state) => state.time.time, (val) => {
  store.dispatch('position/fetchPositionsAtTime', { time: val })
});

If you don't want to watch the state directly you can also watch a getter like so:

store.watch((state, getters) => getters['time/time'], (val) => {
  store.dispatch('position/fetchPositionsAtTime', { time: val })
});

Here's a link to the api documentation for Vuex.Store instances.


Here's an example:

const time = {
  namespaced: true,
  state: {
    time: new Date()
  },
  getters: {
    time: (aState) => aState.time
  },
  mutations: {
    setTime (aState, aTime) {
      aState.time = aTime ;
    }
  }
};

const position = {
  namespaced: true,
  state: {
    positions: {}
  },
  getters: {
    positions: aState => aState.positions
  },
  mutations: {
    setPositions (aState, aPositionArray) {
      aState.positions = aPositionArray ;
    }
  },
  actions: {
    fetchPositionsAtTime ({ dispatch, commit, rootGetters }, { time }) {
      let value = rootGetters['position/positions'].value || 0;
      commit('setPositions', { value: ++value });
    }
  }
};

const store = new Vuex.Store({
  modules: { time, position }    
});

store.watch((state) => state.time.time, (val) => {
  store.dispatch('position/fetchPositionsAtTime', { time: val })
});

new Vue({
  el: '#app',
  store,
  methods: {
    setTime() {
      this.$store.commit('time/setTime', new Date());
    }
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vuex/3.0.1/vuex.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.min.js"></script>

<div id="app">
  time: {{ $store.getters['time/time'] }}
  <br>
  position: {{ $store.getters['position/positions'] }}
  <br>
  <button @click="setTime">Change time</button>
</div>
like image 200
thanksd Avatar answered Sep 17 '22 18:09

thanksd