In the front-end/Javascript world, there was once a time when state management reigned supreme. The dominant player was Redux, primarily used by React developers.
State management has (had) a purpose. It allows you to do things like going backwards and forwards throughout the history of the state, convenient for instances where you need some kind of undo functionality. It can also help you understand what is happening inside of your applications thanks to time travel debugging.
Boilerplate & Buy-in
The biggest downside to state management is boilerplate. Once you do the initial setup of your state management, you can have to adhere to the paradigm of the state library you are using. You need to familiarise yourself with concepts such as reducers, actions and other terms that might not be familiar to newcomers.
Then comes the buy-in. You have to change how you structure and write code to use state management solutions like Redux. This means if you want to change to another state management library later on, you have to go through your app and change over every instance. It's rare that any two state management libraries are alike.
With this buy-in comes lock-in meaning once you commit to state management, it's all or nothing. While there is nothing stopping you from intermixing state management with other approaches, conflicting paradigms null the whole point of even having state management in the first place.
As someone who has had the unfortunate job of tearing state management out of a large-scale web application recently, I can tell you that it is torturous.
If state management solutions existed which were able to be included like jQuery and bam! I have state management, maybe it wouldn't be an issue, but architecting my apps around a library that might be deprecated or obsolete sounds like a maintenance nightmare.
It can complicate forms
I cringe every time I see state management being shoehorned into simple forms and I have never seen it done in a clean and unobtrusive way. Almost every state management solution I know of has a forms plugin, the fact you even need an additional plugin says all you need to know: don't use state management for forms if you can avoid it.
When dealing with form data, in most cases you are dealing with ephemeral state. A login form only exists until the user logs in, the data is sent to the server and then that's it. If you're using React, use useState
if you have too, but making Redux or X name library bend to your will to have a username and password in your state seems like a waste.
In some cases, you might have form-based data that flows over multiple steps. Think of a signup screen where you need to guide the user through steps and then submit at the end? That's a valid use case for state management because you're effectively filling out a large object of data. Still, you could probably use something less complicated to achieve the same thing.
State management for simple booleans? Please stop
Please, for the sake of everyone else around you: stop using state management for loaders and modals. I swear, almost every web application I have seen using state management has loader states and other booleans in state management for the stupidest of things.
I'm sure you've seen isLoading
used more than once or a boolean for showing and hiding a modal before.
Stale data
The age old problem of cache invalidation. I've seen state management used and abused as a form of data cache, fetching some kind of data from the server and storing it locally. Sometimes data doesn't change, but if you're dealing with data that can or will change, invalidating it is another story.
Do you know who solved data caching and invalidation a long time ago? Web browsers. Sometimes a good old fashioned GET request and some properly defined headers is all you need to cache data in your application and have it update when it changes.
Once again, there are solutions out there for these things in state management too. Redux has a trove of plugins that address its shortcomings, for example, but can you imagine buying a car and then continually having to add to it to drive on different roads?
Do you need even need state management?
My advice to anyone starting a new project whether you are using React or Svelte, don't be so quick to reach for state management. It still has merits, time travel debugging and the ability to undo/redo state changes are features I love. But more often than not, you're dealing with data that shouldn't be in state in the first place.
When you use state management I often say, it's like you're building two apps at once.
Top comments (3)
That covers only a tiny part of state management and is more like a convenient side effect of state management solutions like Redux. Depending on the Redux implementation you even need to opt in to keep history and it's often only used for debugging purposes but disabled in release builds.
The main issue is in my opinion, that most frontend developers see an application as a bunch of pages and forms that contain the functionality of the application and they somehow need to communicate a bit.
That's not a very sophisticated view of how to build applications.
If you use an architecture like en.wikipedia.org/wiki/Hexagonal_ar... (or jeffreypalermo.com/2008/07/the-oni...) then you'll see that the Application (core) is independent of the UI. That's quite the opposite of how most client applications are built nowadays, but not because it's better, but because most client applications are built by beginners.
If you use such an architecture you need quite a different point of view.
The application could be driven by a script, or seen as an API, or could have different views like one for mobile, browser, desktop, ... . The application could even be built without making such a decision beforehand. That usually won't be the case though, but thinking this way guides towards a better way of thinking about building applications.
It's also possible to render the same data in different ways in the same application without synchronizing the data between views, because the application holds the state only once an every view is based on the same data. The data changes, all views based on it change at once.
This way the whole application can easily be tested without any UI framework being involved.
All the view (UI) then does is rendering the data that was pushed from the application, and notify the application about user actions the application cares about (button clicked, item selected, ...)
If you use Redux as state management, the whole application is implemented in Redux' actions, effects, and reducers.
Redux also decouples side effects which often are async from pure functions which makes all code that's not side effects much simpler.
Building an application following an architecture like Hexagonal or Onion helps to avoid the tangled mess most client applications are today.
That Redux has often a bad reputation is because most people try to force their primitive approach of building applications onto it and then Redux only gets in the way and development mostly becomes a fight against Redux.
This is what in my experience leads to exactly the opinion about Redux you explained in your article.
So basically the whole article is an explanation how developers (you are not alone here, not at all) see state management before they started getting a basic understanding of software architecture.
Following better architecture patterns is hard to learn, but not because it's a difficult topic, but because the web is flooded with misguided instructions (like this article) but also like the Angular docs or Flutter docs (these I worked with most) and probably most others out there.
Loading flag should be an array of unique IDs or number and not a Boolean. Why? Because there can be multiple resources loading at same time and you might turn Boolean to false if one of them is done loading. If you choose uuid paired with message you can even show what is currently loading in UI.
I think the real game changer for state management is tools like React Query which assume that the vast majority of your state is in displaying data from the server. For applications where this is true, this means assuming that most of the data you care about has either (a) already been fetched from the server or (b) needs to be fetched from the server. When this applies, it's really nice.