What should I do inside a mutation? Can it change other store values, or should I restrict it to changing only the main value? Because if it is the latter I see a redundancy between mutations and actions, actions could access the store directly instead of reinventing the wheel calling a mutation that triggers the "true" change of state.
The difference between actions and mutations is that:
Mutations care about changing the state of only one value?
It can change multiple values, but it must be synchronous.
Isn't this confusing? Or the convention would be for actions to be used mostly for async operations?
Why is it confusing? The doc explains it pretty well I think.
I guess he wants to trigger mutations directly?
Sometimes I feel like I'm writing too much boilerplate, I know that is the cost of the flux approach, but I hope some kind of convention arises that can eliminate part of this.
I think this example may be a little confusing because the actions don't really do anything other than call mutations: http://vuex.vuejs.org/en/data-flow.html
I find it confusing as well. I'm just getting started but already my app seems way cleaner when only using actions. Perhaps I'm missing something, but what do mutations offer? Without looking at the source code, I feel like they are just actions with self imposed limitations (sync, not directly callable, but still callable through dispatch). Mutations would make sense to me if only through them could I mutate state, but we can mutate state through actions as well, so what's the point in using mutations at all? Are there any underlying performance benefits to using mutations vs actions?
Hey everyone. Mutations seems adds a little amount of boilerplate, and sometimes actions just simply reference the mutation.
However this comes with one huge benefit: The logic of the mutation is completely independent of any action. Thus a mutation may have a large degree of complexity, without affecting the overall complexity of the actions flow.
When it comes to debugging an issue it will help to have the flow between mutations and actions more separated. Sometimes a little more boilerplate comes with a lot of benefits, especially when is reduces the overall complexity of something. This isn't really something that is related to vuex but the overall architecture of Flux.
The whole point of a system like vuex is so that every state mutation is trackable. This is why mutations have to be sync.
Imagine you have only actions and you do this:
export function doSomething (store) {
store.state.count++ // <- this can be tracked when this method is called
api.callAsyncMethod(() => {
store.state.count++ // <- this cannot, because it's async
})
}
If you use the logger, you will see doSomething is called, but there will be additional, async state mutations happening afterwards, and when you app gets complex you will have no idea where that mutation came from. This is particularly hard to reason about when calling multiple actions with async mutations, because they can be intertwined!
Actions vs. mutations is all about separating asynchronicity from actual mutations. When you see a sync mutation in the log, you know all the side effects it can ever produce is the different between the before state and after state. But for actions, there's no such guarantee.
:+1:
@yyx990803
I can not use mutations if I do not have asynchronous code in action?
Why mutations in first place?
Could someone just modify the state directly inside a component?
I have prepared a JSFiddle to show an example.
Could someone just modify the state directly inside a component?
That would defeat the purpose of the mutations:
Yes, very often mutations are trivial and that's the cost of this abstraction, but it's not always like that.
I see the point of logging changes to the data, I am still sceptical about the fact that:
It simplifies the interaction with all of your data.
I mean, what's simpler than:
<div v-for="el in mydata.users">
<input v-model="el.name">
<input v-model="el.surname">
</div>
Doing something like this with mutations is horrible. Or am I missing something?
@yyx990803 could you publish the better alternative to the piece of code in your last message and explain a bit in which way is it better?
There are two details which I struggle to understand. One is, why can't the second increment be tracked, but the first one can? (How precisely is the first one tracked?) And the other would be, how does moving the increments to mutations (assuming this is the better alternative) help in each of the two increments?
export function doSomething (store) {
commit('increment_count')
api.callAsyncMethod(() => {
commit('increment_count')
})
}
Both can be "tracked", but the scond one can't be linked to any source from the vuex.
Mutations have to be synchronous so all state changes have happened before the mutation function has finished. Throguh this restriction, it's possible for devtools to record all of the state changes that occurr during a mutation, and hence, allow for a log of mutations and their caused state changes to be recorded and to be undone, re-applied etc. ("time-traveling")
If mutations could be asynchronous (or actions, which can be asynchrnnous, were allowed to change state), then we could not reliably collect information about which mutation/action was the cause of a specific state change - as any such state change could have happened long after the action/mutation has finished (and possibly others have ran in between)
For the next iteration of Vuex, we think we might find a better way than synchronous mutations to work around this issue, but for details you would have to talk to the folks working on it, which is not me.
So using mutations doesn't help in linking state modifications to a "source" (action), right?
Most helpful comment
The whole point of a system like vuex is so that every state mutation is trackable. This is why mutations have to be sync.
Imagine you have only actions and you do this:
If you use the logger, you will see
doSomethingis called, but there will be additional, async state mutations happening afterwards, and when you app gets complex you will have no idea where that mutation came from. This is particularly hard to reason about when calling multiple actions with async mutations, because they can be intertwined!Actions vs. mutations is all about separating asynchronicity from actual mutations. When you see a sync mutation in the log, you know all the side effects it can ever produce is the different between the before state and after state. But for actions, there's no such guarantee.