Reactive Vue 3 State
In this article, take a look at Reactive Vue 3 and see what makes a good application state.
Join the DZone community and get the full member experience.Join For Free
There's been a lot of discussion about state management in the upcoming Vue 3 framework. Some writers go as far as declaring Vuex dead. Reactivity is all we need, is the claim. Just like blockchain was supposed to cure all problems of modern civilization ;-) Jokes aside, it does look like an intriguing possibility, so we've taken a challenge and explored it in this article.
Vue 3 Reactivity System, now free of UI confines, can be efficiently employed as a powerful tool to handle state. This requires extra plumbing though, with no batteries included. If you want to get straight to technical details, scroll down to Reactive proposal for application state chapter below.
The source code for the article can be found at https://bitbucket.org/letsdebugit/vue-3-state. It uses the simple build-less architecture presented in my recent article about Vue JS 3 Application Without Build.
No Need for Vuex?
I've seen many brilliant proposals for managing state using Vue 3 reactivity system. Some would end with a bold conclusion: Vuex is no longer needed. On closer inspection I wasn't so sure. However ingenious, many proposals are essentially just another singleton with a bunch of methods, only made reactive. In all fairness this was perfectly doable with Vue 2 - yet we kept using Vuex. Why? Because there are deeper reasons why we got Vuex, Redux etc. Allow me now to stir a controversy:
A singleton with a bunch of methods is not a replacement for Vuex, even if it's reactive.
What Makes a Good Application State?
A viable solution for application state must include the following:
- Centralized state available to all components. We used to call it a store.
- Functions to safely modify the state, routinely called mutations.
- Ability to modify state in async functions such as API calls. Vuex makes it possible through actions, Redux offers thunks.
- Prevent programmer from shooting himself in the foot by modifying state directly.
It is the last requirement which lacks in majority of the proposals. And for me it is a crucial requirement.
All the effort of writing proper state and mutations is waste of time, if my colleagues are free to modify and hack state directly, causing inconsistencies and elusive bugs.
Vuex helps enforce this with
strict mode, which throws exceptions on attempts to illegally alter the state. Redux resorts to immutability - any local alterations will simply be discarded with the next mutation cycle.
Finally, the mere fact of using Vuex (or Redux etc.) enforces structure and discipline. It does come with the inevitable boilerplate code. But then one simply has to follow the structure - design a state store, define state mutations, organize application logic into actions, create state getters when state gets complex etc.
It's this power of convention which makes your state easier for others to understand and use.
Those who worked on large Angular project without a third party state library immediately know what I'm talking about. Theoretically it is possible to manage state in Angular application using only Angular service and state-as-service pattern. But this is completely voluntary. There are no comprehensive guidelines and patterns of state management in official documentation. The inevitable outcome is a total mess of a state. Mysterious bugs and overwhelmed programmers eventually leaving the ship. Maybe others were luckier, but I have yet to see a large-scale pure Angular application with properly managed state.
That Vue and React both propose a ready pattern for state manegement, cannot be overestimated. Yes, it comes with quirks and boilerplate. But it gives us predictable architecture and much needed rigour. Properly used, it will prevent less experienced programmer from inadvertent or purposeful misbehaviour. Redux and Vuex have trained a whole generation of programmers into full awareness of how to properly manage application state.
Vuex, Redux and alikes are doing great job healing mental damage inflicted by Angular's state-is-not-our-problem policy. Yet so many people still keep asking: "What have the Romans ever done for us?"
Reactive Proposal for Application State
Having praised Vuex, let's try and come up with a simple reactive alternative which meets the criteria specified above. My additional goal is to have as little boilerplate as possible.
This is how I wish I could define a fictional state store representing user session:
Apparently, the only boilerplate here is a call to
createStore method. This is entirely in line with Vue 3 conventions, where we already have things like
Here's how the store can be used in a component:
In HTML template we can refer to the store like this:
Additionally, when programmer attempts to alter state manually, I want the code to throw an exception:
To achieve the above, actually very little code is needed. Thanks to the reactive magic of Vue 3, all it takes is 30 lines of code:
An important addition in my proposal is
extract method returned with the store. It is similar to Vuex
mapState, and it can be used to extract values from state - either direct state properties or state-based expressions, for example:
You might ask, why not simply use destructuring, for example:
This will work, but with a big caveat. The returned values will not be reactive. If you try use them in data bindings, you won't see any changes in the UI, when their value changes. This is nothing unexpected to Vue 3 experts. It's the same behaviour as when extracting values from
props object in
setup method. Vue 3 documentation at https://composition-api.vuejs.org/api.html#setup explicitly warns:
Do NOT destructure the props object, as it will lose reactivity.
This is where our
extract method helps. It not only extracts the required values from the state, but it also wraps them as
computed. This way they can be safely used in data bindings or other computed expressions. Of course, if you don't need reactivity in a particular scenario, you will be fine with simple destructuring.
Please refer to the source code at https://bitbucket.org/letsdebugit/vue-3-state for implementation details.
We've provided a sample application where the proposed solution for state management has been employed. To make it less trivial than the usual single-button click-me application, it has the following features:
- Two views and UI router
- Reusable components
- Two state stores -
sessionStore, used by the views and components as the ultimate source of truth
You can run the sample application here.
It uses a simple architecture presented in my article about Vue JS 3 Application Without Build. To run it, you don't need
webpack or anything else than a modern browser. Serve the source folder with something like serve or
python -m SimpleHTTPServer 8000 and there it is!
We have come up with a simple solution for managing state which seems to meet the basic criteria for a state store. It shows clearly that Vue 3 Reactivity System can be indeed employed as a tool to handle state in Vue 3 applications. Hopefully we'll be able to deploy it soon as a reusable
The article is also available at my blog Let's Debug It.
The complete source code can be found at https://bitbucket.org/letsdebugit/vue-3-state. Feel free to clone and reuse this code. Any suggestions or questions are most welcome!
Published at DZone with permission of Tomasz Waraksa. See the original article here.
Opinions expressed by DZone contributors are their own.