Introduction To Vuex And State Management
State Management can be a hard topic to grasp at first. However, once you start building larger applications with more components, you'll realize that it is an indispensable tool in many of your projects. Fortunately, I have found Vuex's implementation of Flux to be a bit easier to learn than other alternatives, such as Redux for React. So stay strapped and let me give you an introduction to Vuex and the world of state management. 😎
When you first start out building your own Single Page Applications (SPA), you learn about the concepts of props and events to send data between various components. Initially, everything is fine and dandy. However, things can get really messy (and buggy) after you have dozens of components scattered throughout the applications sharing and modifying data.
You get a headache just thinking about it. 😓 Even worse, a global event bus in Vue doesn't really offer a proper long-term solution to your problem.
Just imagine this issue happening on a large scale. Something as big as Facebook... because it DID in fact happen! Luckily, Facebook already suffered for our sins and came up with a solution of their own: the Flux architecture.
Vuex is merely one of many other implementations of this solution.
Before we dive into the logic of Vuex, let's first try to understand the principles behind the Flux pattern. What exactly makes it so great?
First, there's a single source of truth. ☝️ That applies to shared data of course, which is stored in a centralized location. Whatever the state says, goes. Of course, this means that no components may save any copies locally.
Second, changes to this single source of truth are unidirectional! No two-way binding, you filthy peasant! If you wish to alter the state, you must go through a standard process that can be easily traced back, if needed.
This is the opposite to the traditional MVC design pattern where two-way binding isn't uncommon. But again, this gives rise to scaling issues that Facebook encountered.
Alright, with the introduction to state management behind us, it's time we start pounding Vuex into your brain. 🤪
The idea of Vuex is really simple and really similar: store your data in a centralized location that all your components can easily access and mutate. However, components can't just access and mutate the global state willy nilly. Rather, they need to follow a strict set of steps in order to do so. This will make any state changes predictable and traceable.
Vuex works with the following concepts: State, Getters, Mutations, Actions and Modules. Although, Modules will be left out in this article for some other time as they aren't necessary to the Vuex workflow.
The State essentially acts as that "single source of truth" I mentioned earlier in which your application data is stored. It's the equivalent of the data property in a Vue instance, but on a global level instead.
Getters, as the name implies, allow you to get any stored data from the State and are identical to computed properties. This means they are reactive to any dependency changes and can manipulate the output, but not the data itself.
On the other hand, Mutations are functions that are able to update the Vuex state and are equivalent to method properties in a Vue instance (Hmmm, are you starting to see a pattern here? 🤔). However, we have a teeny tiny problem: Mutations only work synchronously.
So it seems that the previously discussed concepts strongly resemble Vue instance properties that we already know and love, but Actions is not one of them. Rather, it addresses the previously mentioned problem by allowing asynchronous operations, or any computations for that matter. Subsequently, Actions call and pass down any data changes to Mutations, as only the latter can mutate the state.
It is generally regarded as a best practice to have an action call a mutation even if it isn't necessary (e.g. you aren't performing any asynchronous operations).
If you didn't understand everything on your first read, don't worry. Before I let you off the hook, I've got a pretty graph to make things easier to understand. 😄
In Image 1, the whole process starts off with a Vue Component calling, aka "dispatching", an action function. Said function might be doing some asynchronous API calls and computations with some data from the state. Next, the action calls a mutation function and "commits" any changes it made to it, i.e. it passes on the new values to it.
Finally, the mutation function updates the state with these changes, or in other words it's "mutating" the state. These changes are automatically updated and rendered in any dependent components.