Starting from a well-known Beatles song title (I know… I am old school/deprecated), I will try to summarize my own experience around state management. I will share my way of “doing it” nowadays with a little help from a couple of very useful libraries. Also, I want to reveal in the following few chapters the experiences and ideas taken from daily work and my teammates over the years that brought me to this point.
There is a beginning for everything…
We can all agree that state management in general is one of the most discussed and applied ideas over the last 6-7 years. I am happy that it was part of my daily work during its evolution path. There are a lot of debates around the “perfect” library for state management, the “perfect” way of data modeling, and of course the strongest debate around the “perfect” paradigm where the battle between functional and object oriented will never end. For sure, these are all constructive and come with real options on the table for every taste. For me, personally, it is hard to say how thankful I am to all the people who worked to develop and promote this idea. I consider they offered more options for building our software design than most of us thought.
First of all, the state management idea completely replaced the MVVM imposed on the market by Angular 1 in a period when some of us did not even imagine an aspect like this. Don’t judge me. I still appreciate a lot what MVVM and Angular 1 made for web development. For sure it was a real rocket for those ages, but the evolution to what we have today, became necessary and somehow inevitable. It’s just that everything has its time… React simply introduced the unidirectional data flow, the idea of state, the reactivity, and the observer pattern in components. So, the rules of the game got changed very fast. Also, the controllers, views, and models started to be a little bit deprecated words in the JS ecosystem. I will try in the next few lines to show how full of intensity was my first interaction with the state management concept.
The pain of the first attempt
After years of jQuery and the magic of Angular 1, I started more than 6 years ago with React+Redux. That was one of the most painful moments in my career. It was hard in the first weeks to adapt my mindset and to accept the functional ideas and the new way of thinking, modeling, handling, and mapping the data.
The first round ended up with a KO victory for React+Redux. This was the starting point for one of the most successful projects and moments in my whole career. I think I was lucky that I started with a library that offers a lot of control over the flow for both actions and data. It enforces immutability in such a way that even a fool can see the benefits after a while, and the tooling for it cannot be ignored. Although I now have various preferences and generally make other choices, my admiration for it is still at the same level.
Another awesome part was that I was simply forced by the project and of course by the respect for clean code, to use it at its maximum level and to have after the whole period, some quite clear pros and cons regarding how a state management should “look like”. The bad part is that even though I implemented/applied most of the things that nowadays are on the market as Redux toolkit, I still had to write a huge amount of code to achieve the usual things.
The design became very composable, making it easy to combine various bits and pieces to achieve the desired state or result. However, for every feature, there were too many subcomponents to be combined and too many files to be added. So, the whole ceremony became rather a treat for a generator and most of the time a real pain for every smart developer.
After this period, every great thing should come to an end. So, a new project came into my professional life with new decisions regarding the tech stack I should use.
A little more wisdom
I felt that going on with the same Redux approach, without getting out of my big comfortable zone, should be a mistake and I should not make the mistake of not being open enough to new things as I was when I picked Redux. The next try was around Mobx, another great popular idea in the last few years. I tried both the Mobx-State-Tree with its functional trends and of course, the well-known “vanilla” Mobx which better satisfies the eyes of OOP fans. Even more, I wrote with typescript decorators a wrapper for Redux that is close in terms of sugar syntax to Mobx API. I think after these two experiences (even if Redux offered me the satisfaction of a great project and I felt I was able to handle everything) that Mobx is a better and more modern approach, a next step in evolution I would say.
It does great things behind the scenes and removes a lot of boilerplate code. It also promotes the easy creation of multiple states, well separated (as a parallel, somehow is the same concept where React won a battle with Angular for creating fast and easy components). Redux has somehow the same possibility, even if it is a single object called state as “the only source of truth”. In the end, that object is separated into all the child nodes you consider as independent pieces necessary for storing things related to a clearly defined object. Also, mapping of “state” in any of the components is not for the whole state, but rather for desired keys from it. In the end, if we judge impartially, almost all of them share similar ideas but are packaged and sold differently.
Enjoy the concept
There are also several others that are very popular and worthy of mention (Jotai, XState or Recoil). Honestly, I consider Redux and Mobx as main trend setters in this field. Every library has its own story. Some of them are very light. Some of them offer a complex API and soome of them promote functions and others promote objects. Each with their own arguments. The greatest thing is that it promotes and encourages:
- usage of the observer pattern
- a clear and unidirectional data flow
- components with almost no business logic
- a very good encapsulation of concepts and features.
Any of these are great in their own way and this paper is not about suggesting one of them. I would rather encourage people to be happy if the project uses any form of state management. Try to use it right. Use all its capabilities and build over main state management ideas in general (and of course, remove the mistakes and all kinds of strange combinations of writing logic everywhere that ends with a merge of “if” statements inside components).
This concept of state management offered a lot, actually a new way of being to the software development world, but if we look behind the exposed API, these libraries are quite easy to understand, without areas with such a complexity that could scare any developer. I would say that is more a lot of sugar syntax over some modern and great practices/patterns. Based on these thoughts and experiences I decided to encourage building a state management mechanism on our own.
I did it my way
To be honest I took part of the idea from the colleague who started the project and applied some reactive concepts quite before they became popular in the JS ecosystem (some people are simply very clever and visionary, and we should respect and be glad that they are around us). I picked the initial idea. “With that little help” from RxJS subjects and Immer the result seems to support the cause for a nice evo-home-made state management.
Below is a GitHub link. There you can see the generic structure of an observable state, the observer React hook, and a very small example of a concrete usage. What you see there is like what we use every day. However, there are several other features that are obviously not representative for this moment. Our states, for example, can broadcast data to other windows. Or they can use the internal subject to create some custom streams with RxJS. Another aspect that may worry some people is the composability of the states. When the composition is about data modeling, the composite design pattern may satisfy the needs. Also, a state can very easily react/subscribe to other state changes.
Check out some code on my Github!
Before I end this little post about such a great and big subject, I want to also share some personal ideas regarding the usage of a state management system. I think we should avoid using it for static data that is initialized at the beginning and remains the same for the whole app lifecycle. I’m using the same approach for any kind of data that is not observable and we shouldn’t monitor its value change.
The authentication token sent for API requests is a good example here. The updates of its value, where this is the case, usually will not request an immediate reaction. Another very important thing is to not store ephemeral data, and this is a quite common mistake for state management. With or even without RxJS it is very easy to write your own messaging system or events bus to decouple areas and to not overuse your state that will then need a lot of cleanup.