How did we get here?
At that time, we had learned that two-way binding is really great but also very difficult to track what changed what and had the easy potential for performance issues (notice I said potential rather than had performance issues, two-way binding itself is not inherently bad by default).
Flux was more of a way of thinking rather than a framework. As a result, many frameworks like Reflux rose and fell over time until we ended up with Redux. Redux took a unique approach of building on a CQRS-like pattern where we would create a global state (interesting enough the opposite of what many of us did) and components would emit events and the store would mutate this state and our components could subscribe to these changes and update from the new state. When I was studying this pattern, I particularly like the event part since that feels really at home in the DOM where we have click events/etc.
As a side effect of this architecture, you have to write a LOT of verbose code. The CQRS pattern is famously known for this problem because it enforces a strict decoupling of state and view. Any component can emit an event and any store can respond to these events and any component can subscribe to any store’s state and update. This breaks from the domain-driven pattern that many of us used at the time where components called specific functions that did specific actions and returned a result.
At the time of creation, the author of Redux Dan Abramov was not working at Facebook. Redux was developed to make it easier for him to debug state changes in the application. At React Europe in 2015, Dan showed off Redux and it was a instant hit. Outside of making application’s easier to debug, Redux also used its global store to give us hot-reloading. This concept would greatly improve our developer experience by allowing us to make changes to the application and have them reload inline with the same state without having to refresh the entire page. Shortly after that, the Redux dev tools was created to allow us to inspect state and debug our applications further.
Shiny ball syndrome…
Like any developer, I have shiny ball syndrome. I instantly wanted to implement this in my application because of these couple of things without understanding the side-effects this might have. Because Redux is so highly decoupled, you have to do a lot of foot work to do even basic things. When you add things like TypeScript, this gets multiplies even further.
We used Redux and similar libraries like NGRX in every application we wrote. Not only does the code get doubled if not tripled in some scenarios, the complexity of your application greatly increases. In some places where you just want to do a simple update like set a todo as done, you create actions, types, reducers, selectors and potentially side-effects for server calls.
As we created more applications, we complained about the amount of boilerplate required to make simple applications. We also tried to get creative and make abstractions that applied domain-driven patterns on top of the event pattern. These types of things completely undermine the pattern because you are breaking the decoupling a pattern like CQRS gives you.
Think before you leap!
The call to action here is to think about this pattern and the side effects it has before you go off and make this investment in a Redux-esque architecture. Sure, with Redux we get those awesome features like dev tools but is it really a good idea to implement this architecture in your pattern just for that. I’ll admit I think they are really useful but I rarely use them once I get beyond the initial architecture glue phase of an application.
Anyone who asks me about state management and if they should use it, I always say if you are asking then you probably don’t need it. Simply put, if your application has got some complex its hard to manage state and data flow, you will know exactly when you need it. What about preparing for the future you might say? I would urge you to really think about where your application will be in the next six months to a year and if its worth it. It never hurts to only use Redux in some parts of your application and not others.
A good example of when you should consider using Redux would be building something like Google Docs. Google Docs has a lot of components that all drive a central editing area. For example, you have buttons like bold the text of the current editing area. The bold button is probably 5 or 6 layers removed from the actual text area. Additionally, you need functions like undo/redo and have real time collaboration where the other users events are being sent to your text area. This is text book example of where Redux would shine.
A bad example in my opinion would be a form heavy application where users fill out an insurance submission form or something along those lines. All the components are close together, the global state of the application is all within one component and there is no external dependencies updating the form.
If not this, then what?
Maybe after you are reading this, I might have convinced you this is not for you. Now your wondering, if not Redux then what should I use?
If you are using Angular, a simple service with an observable will work just fine. You can inject this service to various different components at different levels and subscribe to the result to update your view.
If you are in React, the context API is a really great way to do the same thing, it allows you to create providers and services and access them deeply nested and then subscribe to changes in the view.
Redux is a great architecture and is a great fit for SOME applications but really consider if the value and your sanity are worth the investment.