Vuex is an official plugin for Vue.js which offers a centralised datastore for use within your application. It is heavily influenced by the Flux application architecture which features a unidirectional data flow leading to simpler application design and reasoning.
Within a Vuex application the datastore holds all shared application state. This state is altered by mutations which are performed in response to an action invoking a mutation event via the dispatcher.
An example of the data flow in a Vuex application is outlined in the diagram below. Diagram used under the MIT licence, originally from the Official Vuex GitHub repo.
Individual Vue.js application components can access the store object to retrieve data via getters, which are pure functions returning a read-only copy of the desired data.
Components can have actions which are functions that perform changes to the component's own copy of the data, then use the dispatcher to dispatch a mutation event. This event is then handled by the datastore which updates the state as necessary.
Changes are then automatically reflected throughout the application since all components are reactively bound to the store via their getters.
An example illustrating the use of vuex in a vue project.
const state = {
lastClickTime: null
}
const mutations = {
updateLastClickTime: (state, payload) => {
state.lastClickTime = payload
}
}
const getters = {
getLastClickTime: state => {
return new Date(state.lastClickTime)
}
}
const actions = {
syncUpdateTime: ({ commit }, payload) => {
commit("updateLastClickTime", payload)
},
asyncUpdateTime: ({ commit }, payload) => {
setTimeout(() => {
commit("updateLastClickTime", payload)
}, Math.random() * 5000)
}
}
const store = new Vuex.Store({
state,
getters,
mutations,
actions
})
const { mapActions, mapGetters } = Vuex;
// Vue
const vm = new Vue({
el: '#container',
store,
computed: {
...mapGetters([
'getLastClickTime'
])
},
methods: {
...mapActions([
'syncUpdateTime',
'asyncUpdateTime'
]),
updateTimeSyncTest () {
this.syncUpdateTime(Date.now())
},
updateTimeAsyncTest () {
this.asyncUpdateTime(Date.now())
}
}
})
And the HTML template for the same:
<div id="container">
<p>{{ getLastClickTime || "No time selected yet" }}</p>
<button @click="updateTimeSyncTest">Sync Action test</button>
<button @click="updateTimeAsyncTest">Async Action test</button>
</div>
Here the state contains lastClickTime property initialized as null. This setting up of default values is important to keep the properties reactive. Properties not mentioned in the state will be available but the changes made thereafter would not be accessible by using getters.
The getter used, provides a computed property which will be updated each time a mutation updates the value of the state property.
Only mutations are allowed to change the state and its properties, that said, it does so synchronously only.
An Action can be used in case of asynchronous updates, where the API call (here mocked by the randomly timed setTimeout) can be made in the action, and after getting the response a mutation can be committed to, to make the change to the state.