What's good about Redux
Redux is based on series of really simple what-if questions:
- What if all the data in your app was immutable?
- Okay, now it's stuck. But what if there was only a single solitary mutable variable holding the complete state for your entire app? To change any bit of state, you just assign a slightly different immutable tree to that variable.
- And what if the only way to mutate the state was to create a POJO describing a high-level action, and dispatch it through a single giant processing system, describing the change to make?
A number of interesting advantages follow from sticking to this discipline. It's ideal for ReactJS. You can log everything your users do and replay it, stuff like that. You can store the state snapshots, or just the actions, or both. You can recover your app by loading in an old snapshot and then playing the recent actions to bring it up to date. If you want to know the complete story of how your application ended up in the state it's in now, you've got it. And aside from these nice capabilities, it's worth remembering a lot of bugs arise from fiddling with mutable state at the wrong time. Who needs that?
But just how easy is it to make each bit of your application capable of finding and update the bit of data relevant to itself within the entire state? What about modularity, composability, loose coupling, minimal dependency? It seems that, when I want to change the title of a book, I need to know that the book is in a shelf and the shelf is in a shop, so I can create an action that tells the single global store how to update. The "leaf nodes" of my app seemingly need to know far too much about where they sit in the world. Famously, in purist functional programming, every time I change something I've created a new version of the universe.
Redux as a pattern doesn't rule out interesting solutions to these problems, but nor does it mandate (or provide) them. A common approach in functional programming is the cursor. The originator of Redux, Dan Abramov, points out that classical cursors allow you to directly manipulate data, which then bypasses the idea of high-level actions, so something a little different is needed. I'm thinking of an abstraction that could be called a cursor but which accepts actions.
Redux has also presented a challenge for TypeScript users because of the apparently disconnected nature of the pieces involved. Actions can be independently created, and thrown into the One Giant Store, which then has to figure out what to do. So it seems the store accepts any kind of action across your entire application, and that doesn't sound very static type applicable. Of course this is not a problem that can be solved by saying "Oh, let's not bother with static typing"; more a sign that, because it is difficult to declare the static type relationships, it will be difficult for human beings to manually keep everything straight without any help.
These challenges will be overcome however. The core idea is so simple and enticing, it has to be made to work.