I have several projects at work, such as my Incident Commander application, that could use some refactoring love with regard to state management. I have a sense that using a technology like Redux or NgRx Store would be a value-add. However, I've been having a heck of a hard time wrapping my head around how these state management libraries should be integrated. As such, I read through Taming The State In React: Your Journey To Master Redux And MobX by Robin Wieruch. This book provides a deep dive into state management that is both pragmatic and accessible. It has answered a number of the questions that I had about how state management should be applied; and, has left me feeling more confident about how to move forward in my own refactoring efforts.
In Taming The State, Wieruch uses React as the exploratory context. But, he is very clear from the start that this is just an implementation detail. He chose React because it has a very small API surface-area; but, explains that Redux (and any similar technology) is not tied to React. And that such a library can just as easily be applied to your Single Page Application (SPA) technology of choice (which, in my case, is Angular).
That said, as someone who doesn't use React JS on a regular basis, I did end up learning a few things about React itself. For example, Wieruch demonstrates that the .setState() method in React can be invoked with a partial-state object. But, that doing so can end up leaving the state with unexpected values due to its asynchronous nature. As such, he recommends using the .setState() signature that accepts a callback and provides the previous state as its first argument. This allows the .setState() operation to be turned into a "pure function" that will leave your state in a more consistent manner.
Now, you might be wondering why .setState() was even being discussed in a book about Redux. That's a good observation and it underscores two core tenants of the book: first, that learning is most effective in an iterative manner. And second, that Redux merely compliments local state management, it doesn't replace it.
If you want to learn something, you have to do it step by step. Trying to solve each atomic problem after the next one. Don't apply everything at once. Understand the problem and solve it. That's my attempt with this book: It doesn't only teach Redux in React, but state management in modern applications. It goes beyond the documentation of state management libraries, but applies the learnings in real world applications in the book. (Kindle Location 93)
Trying to understand the extent to which Redux should be woven into an application has been one of my biggest hurdles. So, it was nice that Wieruch was so explicit and opinionated on this topic. His advice was that Redux should be used as little as possible.
In general, the usage of Redux state should be kept to a minimum. A good rule of thumb is to keep the state close to your component with local state but evaluate later whether another party is interested in the state. If another party manages an equivalent state structure in its local state, you could use a reusable higher order component that manages the state. If the state is shared, you could try to lift your state up or down the component hierarchy. However, if lifting state doesn't solve the problem for you, because the state is shared across the application, you should consider to use Redux for it. In the end, after revisiting all your possibilities when only using React's local state, you might not need Redux in your application. (Kindle Location 3313)
To be clear, Wieruch is not advocating against Redux. Nor is he trying to say that it should be minimized. More that it should be "right sized" - that is should only be used as much as is necessary. In the book, Weiruch designates Redux for state that is truly "shared", either by multiple components in the application; or, by a single component across multiple renderings (such as with a data cache). He clearly emphasizes that data shouldn't be thrown into Redux simply because it's there and that it happens to manage state.
This, along with his discussion about normalizing the shape of the Redux state, keeping a "single source of truth" and, using Selectors to generate derived data (based on the normalized state shape) really answered a lot of my questions. I feel like I have a much better understanding of where the lines should be drawn.
That said, from his code snippets, you can tell that such rules are fuzzy and a bit inconsistent. For example, in code that discusses API consumption, he ends up storing the API error message in the Redux store. The error message is neither shared across components; nor is it required across multiple renderings. As such, the error message feels like something that should be designated as Local State, not Global State.
Of course, Wieruch emphasizes pragmatism and iteration throughout the entire book. And, talks about moving state into and out of Redux as it makes sense for the application. As such, I don't believe that he would have any issue with state being "elevated" if it made the code more convenient or easy to maintain.
Personally I would recommend to use such libraries only in two scenarios:
- You want to improve the performance of immutable data structures when using huge amounts of data.
Once Wieruch laid down the fundamental concepts and best practices of Redux, he did go on to discuss Thunks and other asynchronous techniques like Sagas. He covered these topics well. But, there's something about them that my brain just refuses to embrace. Every time I see someone try to push asynchronous control flow into a state-related container, my brain screams, "That belongs in the Controller! That's what Controllers do!". I know this flies in the face of the current Redux zeitgeist; but, Wieruch's explanation of asynchronous control-flow did little to re-educate me on the matter.
Perhaps my brain is just broken?
As a final note, there was something quite pleasing about some of Weiruch's personal views on life. For example, he opens the book with his praise of achieving "flow":
In the book, I want to give you these hands on experiences and challenges to grow. The challenges are meant to create a flow experience, a scenario where the challenge meets your skills and tools at hand. Otherwise, you would feel either overwhelmed or bored. If the book accomplishes to keep this balance of challenging you and respecting your level of skill, you might experience a state of flow. Personally I found this insight astonishing when I read about it, so I hope that I can induce it in this book. It would be the perfect outcome. (Kindle Location 210)
And then, he closes the book with his suggestion that you go forth and teach others about your new experience with Redux and state management. And, not as a marketing ploy; but, rather, as something that will help you continue the learning process:
So here is my quest for you after you read this book. I am sure that you have a friend, coworker or perhaps someone you know only online, from Stack Overflow or Reddit, who is keen to learn about the topics taught in this book. Schedule a get-together with this person and teach him/ her about it. You can take this book as guidance. After all, teaching others is a win-win situation. Both participants, mentor and student, will grow from it. So my advice for you: Become a mentor, teach others and grow. (Kindle Location 4976)
These passages, combined with the rest of the book, gave me the sense that Wieruch has a true passion for learning and for teaching. And, I think this comes through in his opinionated but measured approach to Redux.
NOTE: The part of the book that covers MobX is much shorter. I skimmed it, but did not read it very thoroughly. There's only so many new concepts I can jam in my head at one time.
If you are someone who uses Redux on a regular basis, I am not sure that this book would be much a value-add (though his opinions may be interesting). For me, however, as someone who has been struggling to wrap my head around how Redux should be used, what data should go into Redux, and how derived data should be, well, derived, Taming The State In React by Robin Wieruch really answered a number of questions and helped me build a stronger mental model around shared state.