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)
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>