In Vuex, what is the logic of having both \"actions\" and \"mutations?\"
I understand the logic of components not being able to modify state (which seems smart), but
I have been using Vuex professionally for about 3 years, and here is what I think I have figured out about the essential differences between actions and mutations, how you can benefit from using them well together, and how you can make your life harder if you don't use it well.
The main goal of Vuex is to offer a new pattern to control the behaviour of your application: Reactivity. The idea is to offload the orchestration of the state of your application to a specialized object: a store. It conveniently supplies methods to connect your components directly to your store data to be used at their own convenience. This allows your components to focus on their job: defining a template, style, and basic component behaviour to present to your user. Meanwhile, the store handles the heavy data load.
That is not just the only advantage of this pattern though. The fact that stores are a single source of data for the entirety of your application offers a great potential of re-usability of this data across many components. This isn't the first pattern that attempts to address this issue of cross-component communication, but where it shines is that it forces you to implement a very safe behaviour to your application by basically forbidding your components to modify the state of this shared data, and force it instead to use "public endpoints" to ask for change.
The basic idea is this:
That being said, the magic begins when we start designing our application in this manner. For example:
In the end, we have a user experience that is deemed as "reactive". From the perspective of our user, the item has been deleted immediately. Most of the time, we expect our endpoints to just work, so this is perfect. When it fails, we still have some control over how our application will react, because we have successfully separated the concern of the state of our front-end application, with the actual data.
You don't always need a store, mind you. If you find that you are writing stores that look like this:
export default {
state: {
orders: []
},
mutations: {
ADD_ORDER (state, order) {
state.orders.push(order)
},
DELETE_ORDER (state, orderToDelete) {
state.orders = state.orders.filter(order => order.id !== orderToDelete.id)
}
},
actions: {
addOrder ({commit}, order) {
commit('ADD_ORDER', order)
},
deleteOrder ({commit}, order) {
commit('DELETE_ORDER', order)
}
},
getters: {
orders: state => state.orders
}
}
To me it seems you are only using the store as a data store, and are perhaps missing out on the reactivity aspect of it, by not letting it also take control of variables that your application reacts to. Basically, you can and should probably offload some lines of code written in your components to your stores.