How to find the right state management approach for your app
When it comes to storing data, Vue offers us different options, but which one’s best? And why? Well, it depends on your app really. All applications have different needs and scales. There are multiple factors to consider when making that decision.
Let’s dive into the most common approaches:
- Root Local State
- Vuex library
- Vue 3 composable & reactivity system
Root local state
The concept here is to use the top-level component as a Store. This requires you to pass data down to components using props. In theory, nothing’s wrong with that, this is just the normal flow of Vue. However, it is only ok for tiny applications - 1/2 level deep - after that it creates an anti-pattern known as props drilling.
Let’s say you’ve got a component tree as such:
And you need to pass data like this:
By using the root component as your store, you then have to get back up to the top in order to go back down to components that need updating.
This is not very scalable, it becomes more and more complex as your tree grows and it exposes data to components that don't need it.
Vuex library
To solve this problem, Facebook created Redux in 2015 (based on Flux & ELM architecture) Vuex is the equivalent state management pattern for Vue.
The main concept of this is to aggregate all the local stores of your app into one centralised place and to make it the single source of truth.
By doing so, it allows direct communication between sibling components, in a reactive manner. That means components can now listen for store changes and get updated right away.
More descriptive details on how to use Vuex and why it needs a specific standardisation can be found here.
Well, that’s great, we now have a much better way to handle and organise all our data. But wait, when you think about it Vuex is nothing more than a reactive element that stands out of your app tree right?
Vue 3 composable & reactivity system
In September 2020, Vue released its first stable version of Vue3, which came with a lot of benefits, including the Composition API (inspired by React Hooks).
The general concept behind composition is to break down parts of our component into smaller units and to compose back up greater components with them in order to build our app. This increases code reusability and fixes inheritance issues.
More info about Composition over Inheritance can be found on Wikipedia..
This elegant new way to organise our code allows us to create our own state management system.
Let’s say we’ve got a MyCounter component that simply displays a count value and contains two buttons to increment and decrement it.
In this example above, we are using the component local state to manage the count value and to access methods. By doing so, we are isolating the counter state within that specific component which makes it non-reusable from outside (ie MySecondCounter).
To fix this, we can outtake the logic into its own store and use the composition API to provide and inject the store wherever we need to access it (ie MyCounter & MySecondCounter).
By doing this, we’ve made the counter store accessible from everywhere. You can now simply inject the same store into MySecondCounter component and share the same state.
Conclusion
As seen in this article, all three presented methodologies to manage states can be valid in certain circumstances.
When it comes to choosing between Vuex and Vue 3 composable - in my opinion, there are a few things to consider.
Vuex:
- It forces you to follow a certain pattern. Components trigger actions that call mutations, which then mutate the store. This could become a little verbose as your store grows.
- On the other hand, this protects your store from outside mutations out of the box. This is secure and adds clarity in large scale applications.
Vue 3 composable:
- Not like Vuex, this gives you full power over how you would want to define your store.
- It allows 2-way communication between your view and state which is interesting for style binding. However, you’ll need to manually protect your store from outside mutations if needed by using the readonly methods provided by the composition API.
- Not like Vuex, you will have to inject the store in every component that needs it, this could become a bit redundant.
- Not like Vuex, you can not use the vue-devtools to debug your store, update its state, view mutations in real-time or time travel in your application.