Can someone explain when you would use a dispatch versus a commit?
I understand a commit triggers mutation, and a dispatch triggers an action.
However, isn't a dispatch also a type of action?
As you rightly said, $dispatch
triggers an action, and commit
triggers a mutation. Here is how you can use these concepts:
You always use $dispatch
from your methods in routes / components. $dispatch
sends a message to your vuex store to do some action. The action may be done anytime after the current tick, so that your frontend performance is not affected.
You never commit
from any of your components / routes. It is done only from within an action, and only when you have some data to commit. Reason: commit is synchronous and may freeze your frontend till it is done.
Let's consider this case: If you have to fetch some json data from server. In this case, you need to do this asynchronously so that your user interface is not unresponsive / frozen for a while. So, you simply $dispatch
an action and expect it to be done later. Your action takes up this task, loads data from server and updates your state later.
If you need to know when an action is finished, so that you can display an ajax spinner till then, you may return a Promise as explained below (example: load current user):
Here is how you define the "loadCurrentUser" action:
actions: {
loadCurrentUser(context) {
// Return a promise so that calling method may show an AJAX spinner gif till this is done
return new Promise((resolve, reject) => {
// Load data from server
// Note: you cannot commit here, the data is not available yet
this.$http.get("/api/current-user").then(response => {
// The data is available now. Finally we can commit something
context.commit("saveCurrentUser", response.body) // ref: vue-resource docs
// Now resolve the promise
resolve()
}, response => {
// error in loading data
reject()
})
})
},
// More actions
}
In your mutations handler, you do all the commits originating from actions. Here is how you define the "saveCurrentUser" commit:
mutations: {
saveCurrentUser(state, data) {
Vue.set(state, "currentUser", data)
},
// More commit-handlers (mutations)
}
In your component, when it is created
or mounted
, you just call the action as shown below:
mounted: function() {
// This component just got created. Lets fetch some data here using an action
// TODO: show ajax spinner before dispatching this action
this.$store.dispatch("loadCurrentUser").then(response => {
console.log("Got some data, now lets show something in this component")
// TODO: stop the ajax spinner, loading is done at this point.
}, error => {
console.error("Got nothing from server. Prompt user to check internet connection and try again")
})
}
Returning a Promise as shown above is entirely optional and also a design decision not preferred by everyone. For a detailed discussion on whether to return a Promise or not, you may read the comments under this answer: https://stackoverflow.com/a/40167499/654825