Sense-ible Redux Thunk

Kyle Warren
Common Sense
Published in
3 min readMay 23, 2017

Sense has been all-in on React since we started, but we weren’t always keen on Redux. In fact, when we began building our infrastructure, Flux was only roughly outlined on a Facebook companion site and the community was using a mix of homegrown and open source Flux-like frameworks.

We opted to “roll our own”, watched Redux spawn and snowball, and finally adopted it and redux-thunk when we were comfortable with how much it had matured.

But there were a few things our homegrown Flux framework had that Redux+Thunk didn’t, namely resource caching and request state management, so we brought them over.

The Problem

After developing in Flux for a couple months we realized that most of our action creators and reducers were sharing a lot of common logic. A simple example would look like this.

This action creator kicks off a request to get a user’s data and then dispatches an action to pass the data to a reducer. Along the way it notifies components that it’s fetching and then marks action as cached to avoid redundant requests. This also allows components to show animations while the data is loading.

A corresponding reducer might look like this.

For us it was well and good to write this once, but very quickly it started to feel silly making individual caches for every one of our resources. A central cache made more sense and only required that each resource provide a unique key.

This worked for a while, but there was still a lot of boilerplate code in each action creator. Most of our action creators were dispatching a series of common actions and then returning a promise generated by our api library. The question wasn’t so much “should we refactor this?” but “how?”.

The Solution: “Enter Decorators”

Sometimes, as in most movies, the solution is right under our noses. In this case we looked to the actual Flask API server where Python decorators ruled the land.

Well written decorators are expressive and powerful, but more importantly, they save us from writing a lot of redundant code.

Here’s a decorator that assigns a KEY method to an action creator.

For those unfamiliar with decorators, this probably evokes Callback Hell (a function that returns a function that returns a passed in function), but decorators become more readable over time and look quite a bit like React’s Higher Order Components.

Let’s climb deeper into the crevasse.

Our cached decorator has to make a couple more assumptions about the action creator its wrapping. First, the action creator must have been decorated by the key decorator. Second, it assumes the action creator returns a promise.

But the application of decorators in ECMAScript is still a work in progress, and Babel doesn’t have great support for it. As a vanilla replacement, we use Lodash flow to accomplish the same thing with a little bit more code.

Writing our common caching code as decorators allows us to code action creators that look like this.

Adding comments here feels pretty pointless. We can immediately see what the key for this resource is, that it notifies components that its “fetching”, and that it caches itself. Plus it’s only 7 lines. Now we’re codin’!

And because decorators are opt-in, we can easily add optimizations to our action creators without worrying about the difficulty of rolling them back if they seem like overkill.

Decorators like this aren’t the panacea to all life’s problems; we still have to expose their internal actions (e.g. setCache) to allow more complicated action creators more fine grained control. This is especially important when an action that updates a resource needs to correspondingly bust the cache of an action that fetches it. But they do work for 90% of the action creators we write.

Thanks to Marcos Ojeda and Danny Bowman who developed the Redux and Flux versions of this code respectively.

--

--