Why should you only change state in Vuex through mutations?
It’s a common question I’ve seen around and one that I’ve wondered about myself at times. When using Vuex, why is it said that state should only be changed via mutations? Is it really that big a deal? Can’t I just change it directly? It sure seems to work just fine that way.
Well, yes. And no. And maybe. While it’s possible in Vuex to change the state all willy nilly outside of mutations, it can also fail badly when you least expect it.
The idea of the Flux style of data stores (like Vuex) is that data has a certain path that it flows through. First, it hits an action, then is passed to a mutation and only then is updated in the store. This is done to make debugging and use of the data store easier and not crazy making. If all the components just threw data into the state
willy nilly, then all kinds of chaos could break loose. JavaScript is an asynchronous language and two different parts of the program could be trying to change the same thing at the same time. Reading data? That’s fine. Writing it? You’ve got an issue on your hands.
At least in theory. I’ve written a number of components to try and break this and I haven’t been able to get it to happen. This is mainly because JavaScript is theoretically an asynchronous language. In reality, most of your code will run synchronously and JavaScript will wait for a function to finish before running the next one. So even if two functions get triggered at the same time (like through a timeout or shared event), one will always run first, followed by the other.
This means that mutations aren’t really a consistency feature after all. So are they really still useful?
Yes, because it still gives you a simple structure to follow when writing your code, a structure that you will remember the next time you need to maintain it. If you follow the convention of always changing state with a mutation, then you will always know in your application where the state is being changed.
Mutations are called by components and actions, but not like regular methods. They get “committed”. This just means that when a component wants to change data, the change gets added to a commit queue in the data store and it’s first come, first serve. Things aren’t happening at the same time because Vuex processes the changes in the order it receives them synchronously.
That makes debugging much easier. Seeing strange data where you don’t expect it? Open up the Vue Dev Tools and step through the data store changes one by one. Each change to the data store will be “committed” and you’ll be able to roll it back and see everything that led up to that point. This logging is the real reason you should only change the state with mutations.