When I first blogged about Redux in August of 2015 the opening line of the post read:
Every once in a while something new comes along that just feels right.
When this happens, I get a tingly feeling in my left pinky toe. That’s how I know it’s not just a fad. It’s how I know it’s legit.
I then went on to introduce the basic ideas of Redux and why I liked it so much. It's quite amazing to see what's happened since that time. Redux has grown to become so commonplace that many derivations have been created; it's arguably worth learning even if you never actually use it, so you understand what's going on when you hear it discussed. By having an understanding of the patterns used by Redux you'll be far better equipped to understand a whole slew of related problems, tools, and solutions.
Redux itself is a relatively simple idea, but as it turns out, using it to build real applications is not all that simple. But to be fair, Redux never claimed to be particularly opinionated or complete. After all, it's just a state management library, not an application framework. So, beyond a few basics, Redux doesn't impose any inherent structure. In that sense, it's not so different from React, in that it's just a tool. You can build fantastic apps with these tools, or you can make an absolute mess.
Redux puts the weight of architecture decisions on you the developer. This gap is what I'm going to attempt to fill with this book.
Who are you, anyway?
I've personally been trying to build ambitious mobile web apps since 2009. First, just making apps for myself using jQuery, jQTouch, and jQuery UI. Then in 2010, I started working full time at a consultancy. This new position exposed me to a slew of different projects at various companies, each with their own set of problems. I zeroed in on "real-time" web apps where data was pushed from the server to the browser. We built an incredibly complex asset tracking app for one client, involving high-accuracy tracking devices on a map moving around live in front of you. Some even had barometers on them, so if someone had a sensor in a briefcase and got into an elevator we could determine what floor of a building it was on, and the map would switch to the relevant floor-plan.
I built several different chat applications, including a team chat product—this was before tools like Slack and HipChat became popular. We were early adopters of Backbone.js. I gave my first conference talk at the very first Node.js Conference, called "Building Real-time Web Apps with Backbone." I later gave a similar talk at BackboneConf. After pushing the limits of Backbone.js, Philip Roberts and I (whom you may know from his incredibly popular talk "What the heck is the event loop anyway?") decided to make a framework that elaborated on what we liked about Backbone, and we created Ampersand.js. Incidentally, Ampersand.js focused heavily on the state management problem. It was around this time I was working on a contract with the AT&T Foundry, which is AT&T's internal innovation lab in Palo Alto. Among other things, we built an app that let you make and receive real phone calls in your browser. This work was showcased at CES the next year. Through all that I learned enough about WebRTC to build what was probably the first app to do 3-way video calls between Chrome and Firefox. We launched an app as a demo called Talky.io, and I created a library called SimpleWebRTC that became very popular.
I mention all of this to demonstrate that when I say "ambitious web apps" I'm not talking about simple websites; there's no doubt these were applications in every sense of the word, they just happened to be running on The Web platform.
In trying to build ambitious apps like these with a variety of teams, I've identified what I believe to be the two hardest problems for web developers:
- Managing complexity of your code base as it grows and as requirements shift
- Managing application state
Not long after this, React started becoming wildly popular. I was among the scoffers initially, but the idea grew on me because of the simplicity of the "point in time" rendering model and the simplicity of composing a view by nesting components. But, while React provided a more straightforward way to render the UI, I still needed some way to manage application state. So I used Ampersand.js Models for managing application state and then just replaced my views with React. This approach worked well enough; I taught a Frontend Masters course using this approach, and even WhatsApp.com used this combo for a while.
But gradually, I came to realize that many of the features we had built into Ampersand models were not needed with this new rendering approach. But, I wasn't sure what else to use. There were a lot of options out there, but nothing quite clicked. Jing Chen from Facebook had created a pattern called Flux. Flux was revolutionary in that it eschewed traditional Model View Controller approaches and instead used a pattern of dispatching what she called "actions" through "state stores" to update them. However, none of the libraries that were trying to implement her pattern appealed to me, and nothing else I looked at really seemed quite right.
Then one day I saw Dan Abramov's talk at ReactEurope introducing Redux, which borrows many ideas from Flux, but wraps it up into a nice little package with a single "state store." It just made so much sense to me. I got super excited and wrote that blog post. I haven't looked back since, and I've been using Redux for everything. There's some discussion as to when you should introduce Redux into your app. Even Dan Abramov says not to use Redux until you actually need it. As I'll discuss, we can do simple things with just local component state. But personally, I've yet to make a whole app where I didn't eventually want something else to help manage my application state. Perhaps that's just because of the types of apps I like to build, or because I prefer to separate application logic from my components. Regardless, if you're reading this book, odds are you've struggled with managing complex state just like I have, and you want patterns to help you cope with it. I feel like Redux, when used well, tackles this problem better than anything else I've seen.
Initially I built a few small apps with it on my own, but later I was brought on as a contractor to work with the development team at Starbucks. They had just started transitioning some of their web properties from .NET to node.js, Redux, and React. Here's where I gained experience with Redux at scale, at a large company, with dozens of developers working with it together. First, we were building distinct apps in different teams. Then, at one point I was given the leeway to prototype a Progressive Web App. Over time, with the help of lots of folks, we folded all the other individual apps into it that prototype and soon it was no longer a prototype. As of this writing, it's deployed to all U.S.-based customers and from what I last heard, will be expanded farther.
I think it's safe to say we tested the limits of Redux. At times we had performance problems to address, we had challenges of maintaining consistent usage patterns between teams, and then the challenge of combining all of these disparate pieces, initially developed as separate apps, into one cohesive app. Ultimately, Redux stood up to the challenge.
Granted, many of the problems we tackled at Starbucks are not typical of all projects. But the year and a half at Starbucks pushing Redux to its limits proved to be very educational. I've since moved on to build other things, but I'll be pulling in a few relevant anecdotes from my experiences there throughout the book.
So, here we are again.
Build ambitious web apps while managing complexity.
I've organized the book into two main parts:
Part 1: Redux Basics
In Part 1 I'll provide a gradual introduction to the ideas and main APIs of Redux. This part is not meant to be a replacement for the official documentation. The official documentation is excellent. I'll focus on the how and why of Redux, not just the mechanics. If you're new to Redux, this way of explaining it has worked well for students in my workshops and may give you a gentler introduction than you'd get reading the documentation. If you've used Redux, the mechanics may be old news, but I don't hold my opinions back in this section either. Hopefully, it will provide some new perspectives even if you're quite experienced.
Part 2: Redux Patterns
In Part 2 I'll present the patterns and approaches that have proven themselves to work well, and cover topics such as:
- How to express complex logic without complex code
- How to build super resilient apps that not only tolerate, but expect and recover from failure
- How to manage the challenges of client-side caching (versioning, cache invalidation, and max age)
- How to let Redux handle routing
- How to keep your apps fast and tiny
- How you can run your entire Redux store in a WebWorker
What follows are my highly opinionated perspectives on Redux and the patterns that have worked well for me.
I hope you find them useful as well.
There are several runnable demos and example apps that are referenced throughout the book. For simplicity, most of them are on CodeSandbox.io. If you're not familiar with CodeSandbox, it makes it easy to see both the code and the resulting app without the need to install or run anything locally. If you prefer to run them locally, look for the download button on CodeSandbox.io to download the project as a Zip file. Make sure you have the latest stable version of node.js installed, then run
npm install and
npm start in the unzipped project directory. There's also a list of all the referenced examples in the appendix.
I'd also like to say a big "thank you" to the people who were kind enough to review this book. Their feedback dramatically improved what you're about to read. I'd strongly encourage you to follow them and their work: