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)
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 .
This Vuex plugin allows you to sync and share the status of your Vue application across multiple tabs or windows using the local storage.
Note we are performing a flow of asynchronous operations, and recording the side effects (state mutations) of the action by committing them.
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.
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>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With