Learn Something New Everyday,
Connect With The Best Developers!

Sign Up Now!

& 500k+ others use Hashnode actively.

James Clarke's photo

Hi Andrew! Glad that you are doing an AMA here. :)

What was the initial motivation behind building Redux? What were state management problems you faced that led to Redux.

Andrew Clark's photo

Front-end engineer at Facebook

Hi James! Dan and I came at it from slightly different perspectives, so I'll describe the arc of Redux history as I saw it.

Before Redux, I created a Flux library called Flummox. This was during the time that a new Flux library was coming out every week. The initial motivation for Flummox was that I needed to do server-side rendering. Few of the existing libraries supported this because they relied on singleton stores. I tried to design Flummox as a thin layer on top of Facebook's Flux dispatcher, with a store API that mirrored the React component API (e.g. stores had a setState method that automatically emitted a change event). In retrospect, there were a few unfortunate design choices, but there are three that really stuck: the idea of action creators as functions that return action objects; using React context instead of singletons; and using React components (and higher-order components) to connect to your stores (instead of mixins as most libraries did at the time). All of these points influenced the design of Redux.

Meanwhile, Dan was working on a talk for React Europe 2015 on time-travel and hot reloading Flux stores. Dan was a Flummox user in early 2015, using it as part of React DnD. This is how I originally met him.

There were a few other cool Flux libraries floating around at the time. I remember NuclearJS and Om being especially influential. The idea of a more functional Flux, where updates are expressed as functions of the previous state, and state is kept in a single immutable object — those concepts predate Redux. I remember lots of discussion with Dan and others in the community about how to apply these concepts to the Flux pattern.

Dan's original version of Redux contained the key insight that there's really no need to have multiple, stateful stores in Flux. Instead you had "stateless stores" that returned a new state given the previous state and an action. We later, of course, renamed these to reducers. This initial version was pretty cool, and could do time travel and hot reloading, but it didn't have some of the other aspects of Redux that we know today. There was no single, immutable state value. On every dispatch, Redux would iterate through every "stateless store," compute the new state for that store, then combine the states together. There was also some logic to only emit change events to components that had subscribed to a specific store, for performance. (This was later replaced with selectors and shouldComponentUpdate optimizations.) There was also no such thing as middleware — there was basic async support built-in, which we later extracted into redux-thunk.

An important bit of the original Redux was the lack of waitFor. One of the things previous functional Flux experiments struggled with was how to account for this feature, which in traditional Flux is used to deal with dependencies between stores. Dan recognized that this can instead be solved instead using composition. (https://gist.github.com/gaearon/d77ca812015c0356654f)

This was a eureka moment for me. Building off Dan's idea, I realized that you could also use function composition to avoid having to keep track of many "stateless stores," and instead combine them together into one. I stayed up all night and sent Dan a prototype illustrating this concept (by happy coincidence, this happened on Dan's birthday!): https://gist.github.com/acdlite/9f1b5883d132ad242323

There's some weird terminology in that prototype, but in it you will find the genesis of many of the key concepts that make up Redux today: reducer composition (combineReducers), a single state value, and selectors. This updated design also had the happy side-effect of dramatically reducing the amount of code needed to implement Redux, as anyone who has completed Dan's Egghead Redux courses can tell you.

Another key concept in Redux, middleware, came soon after. If you're interested, I encourage you look back at some of the early PRs and issues. There was lots of back and forth between Dan and me (and other collaborators) about how to make Redux extensible, so that it's hard to remember who came up with what exactly. The way I remember it, Dan came up with the idea of what was later called "store enhancers," which we also sometimes called "Redux inception" (turns out, this is just a flavor of the Elm Architecture). I came up with middleware based on a pattern used by Flummox internally to support promises. The truth, though, is that these patterns were the result of extensive collaboration and experimentation, so it would be wrong to attribute them to any one person.

Middleware and enhancers are perhaps the two bits of Redux that I'm most proud of, because it allowed us to keep Redux really small and focused, and enable amazing community projects like redux-saga and redux-observable. In other words, middleware and enhancers effectively killed the new-flux-framework-every-week trend because you no longer had to create an entire library to implement a single idea. Without this, I doubt the Redux community would have lasted as long as it has.

So that's the basic overview. There's so much detail that I've left out, but I've gone on too long already. Perhaps I'll cover the rest in my response to other questions :)

Dan Abramov's photo

Terrific answer by Andrew. I'd just add he's being humble, and middleware was mostly his design. I was just merging whatever PRs he was sending because I was busy trying to get my conf talk demo working :P.

But seriously, I suggest to read early issue and PR discussions, they're a lot of fun to revisit now.

https://github.com/reactjs/redux/issues/6 https://github.com/reactjs/redux/pull/195 https://github.com/reactjs/redux/issues/113

Want to read more?

Browse featured discussions

© 2020 · Hashnode