Redux-First Router data-fetching: solving the 80% use case for async Middleware

James Gillmore
Jul 19, 2017 · 26 min read
your routesMap configuration — notice the thunk option

Understanding the architectural decisions behind the tools you are using is perhaps more important than the many things a new package does for you.

The reason is because once we reach a certain skill level in our journey, we become aware of the many ways to do the same things, and expend too much time wondering if we’re doing things the best way.

The goal is to get past the point of second-guessing ourselves and to become confident in the path we've chosen so we can execute quickly and efficiently.

But that doesn’t mean we shouldn’t listen to our gut instinct. Sometimes we know deep down, even though we are using the fanciest, say, async middleware —— we still aren’t doing it the “correct way.”

The only way to truly stop second-guessing ourselves is do things the “best way.” When the signals inside yourself stop, you know you’ve selected the correct strategy for this juncture in your journey. This isn’t an uncommon occurrence for the persistent developer — and when we have the luxury we should always pursue it.


Today I’m going to explain why Redux-First Router’s data-fetching strategy is a sound and powerful strategy

The 80% use-case for async middleware is dispatching 2 actions in sequence: the synchronous “setup action” ™ and an asynchronous “follow-up action” ™.

Before we start, I want to plant a concept in your mind so you have a frame of reference — there are 2 primary data-fetching strategies for React:

Async middleware falls in the second category — just without ™ unless you’re using Redux-First Router.

What it is though, is an vs. . We will tackle the problems with before getting to why current middleware strategies are too complex and miss the mark for the 80% use case.


Pairing data to components makes a whole lot of sense when you have a system like Apollo that handles all the nuances for you (particularly promise resolution on the server). Without it, not so much.

There‘s a hype train around pairing non-GraphQL data to components via .

In the majority of cases data can be paired to the route, i.e. the URL and parameters in the URL. How to get a “” on the route will unveil itself later in the article. Here are the reasons why data deps are preferable:

Those are things you want. Those are things that make your life far easier. They can be summarized as:



That’s the question you must ask yourself to make the best decision here.

Well, let’s talk about Apollo for a second. And the reason I don’t mention is because Apollo works with Redux and since UI-state is so important — I want something made for Redux. The story is over in my mind. However, when I say “Apollo” I really mean Apollo Relay or similar.

So what do you get from “Apollo”?

You’re basically distilling what otherwise is a never-ending boilerplate creation process into the purest definition of what you need, That’s great power! That makes the bulleted of route-paired data deps worth going without.

That’s the only time I would recommend not fetching data in a way paired to your routes. I.e. when you get all these extra perks, and a fantastic feature-complete library to bring it all full circle.


Now for the rest of us: if you’ve gotten to fetching data in , you’re doing it “wrong.” Unless you have these needs:

  • ; so it’s helpful/required to guarantee components for new features have all the data they depend on. Huge companies with many developers working on big apps (ahem, Facebook) have this problem. It’s the reason Relay was created. Very few apps fall into this category — it’s the of added complexity for features you don’t in fact need. (unavoidable reason)
  • ; it’s easierreadsto write the custom logic at the component level, even if it means an additional fetch. (bad reason, especially if you’re server-rendering)
  • . Solving this one is what Redux-First Router is all about. Any action can now be It’s an excuse if you haven’t URL-ized most of your actions. (bad reason, but only really possible thanks to RFR)
  • If you have this problem, you’re likely doing something wrong and need to get better use out of Redux. Or somehow you’ve dug yourself into this hole after months of development and there’s no going back. (bad reason / unavoidable reason)

Fetching data in componentDidMount is the modern incarnation of the fat views/controllers anti-pattern.

The problem has been we have had no good designated place for “controllers” …until now.

So bottom line is all the reasons above are either or you can’t control. If it’s the former, the examples soon to come will help. If you’re in the latter case, I feel for you. I suspect it’s because you’re in a large organization with serious apps and old APIs. Maybe it’s time to make a push for an Apollo/GraphQL overhaul.

I don’t propose to have solutions for everyone. My goal is first to help you see the difference between and


To be able to accomplish route-paired data fetching, you have to ask yourself one question:

Is all the information I need in the URL or cookies?

Keep in mind request headers only apply to ajax requests, as you can’t control the headers sent when users visit your website directly. That point is more important than ever now that universal code-split apps is a solved problem.


You “shouldn’t” be making your app as an SPA if you’re a “power user.” You’re losing customers from google. And the time till interactive (TTI) is slower, which not only bounces a higher percentage of your visitors but compounds the google problem since google likes fast sites, etc.

In general, if you’re not server rendering your app and code splitting you’re losing users/customers/money. The only reason ever to make the tradeoff between one or the other was because the development costs of trying to do were too high. And guess what? I’ve spent like 6 months on that problem alone so you don’t have to :)


Ok, let’s get back to business: you have the URL + cookies. Cookies means you have your user. So let’s distill what you have down to URL parameters (via path or query) and the knowledge of which user is visiting your site.

So the question is (since we are diligent developers who refuse to have blind spots):

The reality is for greenfield apps which can control what URLs they’re using, you’re not missing anything. Put every bit of state that otherwise would only exist in the component tree or your redux store in the URL. That is: every bit of from which everything else can be derived Story over.

You only want to do the former when you truly have to. The primary reason component-paired data is “bad” is because you don’t have Apollo at your service on the server recursively resolving promises attached to components.

Keep in mind with all this, the problem primarily exists server-side. The nature of handling requests on the server is . Regardless of whether you use async/await, a request is handled by you fulfilling a to-do list.

On the client where you have a “breathing” app responding to user inputs/events, child components within your tree can respond individually. It’s truly . In this case, component-paired data fetching is a nice impedance match.

So on the server you want to respond to incoming requests as quickly as possible. And to do so, it must be in a way that makes use of the state initially supplied: . That’s where the sequential/synchronous thing plays out.

Rendering twice — if only in the virtual DOM one of those times — is precious cycles one day you will wish you conserved. If it results in multiple non-parallel requests for data, even worse. Nobody’s saying don’t use Apollo. Use it in places other than your high-trafficked public portions of your site.

Bottom line: Apollo lends itself to a nice workflow, but not one you want to get carried away with when it comes to server-rendering, or you’ll have longer response times. It’s great for private areas of your web app where SEO doesn’t matter React Native. That is to say, public portions of your web applications are very important. It’s where you get your users/customers from. If you can distill all data-fetching on the server to one database request you’re literally making money.

componentDidMount WITHOUT APOLLO

As for componentDidMount without Apollo, there are various reasons people have gravitated toward data fetching in .

The primary one is likely that they don’t have Redux under control. And if they are using Redux they don’t have their async middleware under wraps. They might not even have it at all. It’s this category of users that are hell bent on fetching data in stateful components.

It may also be a matter of habit — a habit that started before they introduced Redux to their app.

That’s not to say that the componentDidMount “workflow” isn’t at times a useful one, even for the most advanced Redux developers. Sometimes you just want to get your component working and want to fetch the data right where you are without visiting other “boilerplate.” Or you want to use the component in multiple places and be sure it will have all its data-dependencies. If SSR isn’t on your radar, it’s easy to see why componentDidMount is a viable option.

The thing is important. Let’s not discount it. RFR also has a nice workflow. Once u have your actions, it’s extremely intuitive to pair a data dependency to an action in the form of a thunk. It’s a nice convergence of typical Redux patterns and terminology with routing.


We’re going to assume you understand/agree_with the importance of the URL, and you’re very that you can refine critical URL state into application Redux state.

So assuming you understand that and your plan is to pre-populate your Redux store and then render, what options are available to you to best populate your store:

It’s basically all the same stuff. And you have options. Options of what asynchronous middleware to use. Options of when to parse the URL and what to initially dispatch. We won’t have the debate today — because the answer is you can still use them with Redux-First Router. The recommendation is you use them where they shine though.

Even though Redux-First Router includes a middleware, it’s important to think of it as something simpler than that.

What all the above solutions have in common is that you dispatch a synchronous and a is dispatched a few ticks/milliseconds/seconds later with the data. Asynchronously.

In other words, the vast majority of the time you simply want to set an initial state, and then set a second state depending on how the data fetching job went.

Sagas and Observables gives you tremendous power to go far beyond this, allowing you to listen to complex/multiple inputs and dispatch however many follow-up async actions you need. But that doesn’t change the fact that most of the time it’s just one upfront and one after. That’s the 80% use-case. The 80% use-case for Redux middleware is dispatching 2 actions in sequence: the synchronous and an asynchronous

So since RFR works beautifully with Sagas etc , wouldn’t it be nice to have a stupid simple idiomatic solution for these ever-common back-to-back dispatches?

Yes, and the answer is to pair follow-up actions to their trigger/setup action in an idiomatic way. Perhaps a config object, namely a route.

2 routes in Redux-First Router — one dispatch in your thunk (aka “follow-up action”)

Each route in RFR is basically an action. It’s a way to apply more context to your actions. The core of that context is that each action corresponds to a precise URL. But there are also more things you can do — from prefetching chunks , prefetching data , to what we will be talking about for the remainder of this article and the most important thing (as well as the basis for ):

Each route config object has a thunk option, which looks just like the thunk functions you dispatch to

The reason you don’t need to waste your energy dispatching a setup action within your thunk is because . When that URL is “visited” the corresponding action with path params extracted into the payload will be dispatched.

{ type: ‘LIST’, payload: { category: ‘javascript’ } }

So to reiterate, thanks to the context you can skip manually dispatching the setup action. It’s a small win, but as the benefits of URL-centric config unfolds, wins will mount up.


When you can distill solutions down to config objects, rather than ad-hoc code, you achieve great justice.

Truth is I came into this game — like many — in an era of MVC frameworks where all the rage was “convention over configuration.” And I still don’t know what that means — it seems both overlap quite a bit.

You remember XML right? A tool used for configuration. Well HTML is XML, or sub or superset of it or . And React specifically chose the JSX route. Why? Because “declarative” coding is half way from “imperative” coding to configuration. JSX is essentially configuration with a backdoor to write ad-hoc imperative code when you need to.

It depends on your definition of “imperative,” but I just mean you can write plain procedural javascript in your otherwise pure declarative component functions.

So, it’s for this reason that Sagas and Observables and ad-hoc thunks are closer on the to the imperative side. Being able to define your thunks in a route configuration gives more meaning to those thunks, locks them in, and is therefore closer to the configuration/declarative side.

So that’s the premise of route thunks — meaningful URL context. You know exactly where your data dependencies are supposed to go. And that place is closest to URL state — the only state (minus your user session cookie) that you can synchronously render from.


As for — it falls into the same category. That category is state you know upfront before you render your component tree.

The strategy for that is to call createStore server side with initial state containing your user object which you retrieved using a session cookie or JSON Web Token (also in the form of a cookie).

This article won’t tackle auth and the user session cookie, but the point is it’s — so we can check it off in our minds. And similarly to how we call all client-side GraphQL caches simply we’ll continue to call state from the URL even though it includes the user session cookie: or


To make sure we’re on the same page, let’s talk about “contracts” and what Redux’s core “” was all about. The contract is:

  • your “UI database” is derived from pure functions called reducers
  • your reducers respond to serializable actions; that is, you can’t set state directly; you have to do so indirectly through the combination of actions + reducers

That’s the contract. The gains this gives you is 100% predictable state, and subsequently predictable view rendering.

These gains extend so far that you can provide the same sequence of actions and be guaranteed the same resulting state.

With this foundation, the opportunity of time-traveling debugging unveils itself as well as everything you see in the . I live in there. If you build Redux apps, you probably use that far more than the .

I remember the days when I used to debug in Chrome all the time. The Redux Devtools has basically displaced that too if you’re doing a good job at building your app out of pure functions, pure components, pure reducers, .

If you are doing those things, the Redux Devtools can answer your most common questions:

Subsequently since debugging these 2 are easy, and since pure components are also so damn easy to deal with, your primary bottleneck becomes the asynchronicity of data fetching + multiple dispatches.

Where RFR really shines is that in the midst of the asynchronous data fetching challenge, you don’t have to deal with the URL. Just make sure the actions dispatched have a route matching it — once in the beginning when you initially setup your app (or every so often when you add a new feature).

It makes the URL an after-thought. And not an after-thought that causes you problems because you now have to re-architect your app. And certainly not something that requires additional dispatches.

See, that’s part of the problem here — developers end up dispatching too many actions. For example, in my apps, I do everything I can to avoid actions that dispatch one after another. I consider that “incorrect”.

Any time I’m tempted to dispatch consecutive synchronous actions, I instead figure out how to make my reducers respond correctly as if only one of the actions was dispatched.

Your reducers should be able to fully respond to the first action. There are reasons for batching middleware, but most of the time it’s an anti-pattern.

So if you have things setup where you have to dispatch one action to display one thing, another action to display something else, and yet another subsequent action (or function call) to change the URL, you’re definitely doing it wrong. Or it’s because you don’t have something like Redux-First Router at your service, and instead you’re littering lifecycle methods throughout your component tree with ad-hoc component-level dispatches.

In other words, component-level dispatches is the #1 cause of multiple synchronous dispatches, and ultimately crummy rendering performance + a disorganized redux architecture.

To be clear, there’s always an exception to the rule. Today we’re talking about the 80%, not the 20% of the 80/20 rule.


So with a 2nd problem out of your way (i.e. URL-management + keeping everything in sync), you have relieved a lot of pressure and complexity from your async data fetching.

Data-fetching now boils down to:

  • the user reaching a URL (no work for you)
  • you requesting some data (less work: no setup action)
  • making a decision on what to do with it & dispatching a single follow-up action (now better in focus as your sole task)

That follow-up action may be one of many possible actions. For example, if the user visits, you dispatch a follow-up action that retrieves various related entities (based on the slug) you’d like to display.

Or if the user visits without being logged-in, you redirect back to the /login form. And if the user is logged-in, you asynchronously fetch some data you will need to display within their dashboard:

QUICK, ANSWER THIS: how do we trigger the loading spinner until ENTITIES_FETCHED is dispatched?

You no longer should worry about dispatching an initial setup action, as by virtue of visiting /me and the ME type being dispatched, your reducers should know to display spinners if the data isn’t cached.

As you can see, RFR offers a redirect action creator. It’s one of the few such utilities offered by the library, as the goal is to keep the API surface to a minimum. Most of your work is in the one-time setup of your routesMap and continued work via typical Redux patterns (e.g. within your reducers, connecting components, etc).

…While we’re here, another thing worth looking at is how routes NOT_FOUND can be addressed:

Dispatching the NOT_FOUND type exported from RFR is a solution for when you throw your hands up and don’t know exactly what to render because you didn’t get the data you needed —

You can simply dispatch NOT_FOUND, and depending on whether RFR can infer the URL or not, it will display the correct URL (even though it doesn’t have the data for it), or your notFoundPath as supplied as an option to connectRoutes.

From there it’s up to your reducers to determine what to display (when it receives the NOT_FOUND type) as they usually would.

Why do we bring up dispatching NOT_FOUND? Because like redirects, it’s part of the idiomatic ways to use your route thunks.


The takeaway is you no longer have files full of ad-hoc action creator thunks that do who knows what. If that’s the path you took, you’re left having to read the comments to remember how everything works. See, the thing is URLs are something to be taken seriously. They force you to encode your app in as logical of a way as possible. They are much needed structure — — that keep the actions your app deals with to a minimum.

When you see a thunk corresponds to a URL (say your /login path), and because of that you know it’s the only thunk that can handle that URL, you know exactly what to expect of that thunk. And you know no other thunks can deal with it.

You will inevitably struggle to manage your exponentially growing number of action creators if you treat them as setters. Having URL-ized actions prevents you from creating more actions than you need. As a result your reducers become fatter and smarter.

Whereas before they might have looked like this:

Now they look like this:

So in the former you often end up dispatching SIDEBAR_OPEN right after another action that does something else. Or at least you can easily fall into this trap.


The fact of the matter is Redux took us in a direction where anything and everything became possible. And since users are likely to trigger all sorts of events, it became a nice way to be able to deal with anything that comes our way.

So with that flexibility, and React Router tricking us into thinking we were doing it the right way (by dealing with URL state within the ), we forgot the old wisdom of MVC.

In MVC terms, React is the V, Redux the M, and RFR the C.

If you’re like me, you thought the MVC pattern was dead.

Bottom line: because new powerful tools have made all the possibilities RFR gives us much structure in a world where we desperately need it. We have become children in desperate need of structure.

As in the initial RFR pre-release article, it’s been a case of getting lost along our way as new things opened up the pandora’s box of options.

In the RFR Pre-Release article, I describe how the “everything is a component” strategy is essentially a workaround for not having a client-side database like Redux synced with URL state.

In this article, we’ve debunked how fancy middleware is a workaround for not having a proper routing mechanism and its corresponding contextual structure (i.e. its routesMap).

To be clear, RFR is a middleware. It’s a middleware, enhancer, reducer, set of action creators and Link components (but no Route components). The middleware is probably the biggest part. So it is a middleware just like the others, but rather than give you infinite flexibility, it constrains you via just like Dan Abramov promoted was what Redux owed its true power/utility to.

RFR isn’t the first router or framework to provide you a defined place to request data in response to path + query params. To seasoned developers, this isn’t anything new. What RFR is, is the first solution to take MVC to heart and apply it to a Redux-specific context — after a period where MVC has been anathema to everyone.

At the end of the day, you’re using routing to do the same thing you do the bulk of the time in more complicated super flexible middleware. Even if a few people manage to come up with some discrepancies and edge cases, you’re covering somewhere between 75 and 95% of all cases by having thunks attached to


To wrap things up let’s do a final comparison between the old ways and the new Redux-First Router way.

If you made it this far, you deserve a break; play this song while you review the code comparison that follows (i.e. the real meat of this article)

Old componentDidMount + react-router + redux-thunk way vs. RFR way:

OLD componentDidMount WAY

Take note of the way react-router state contained within the view layer (ownProps.match.params.category) is combined with Redux state to derive the final state, as well as to dispatch current and future actions via requestVideos within componentDidMount , componentWillReceiveProps.


The primary thing to notice in the new way — besides that it’s half the size — is that the requestVideos thunk has moved to a permanent place as the value of a route’s thunk. In both cases they are standard Redux thunks that receive dispatch and getState arguments. However, when using Redux-First Router, you no longer need to dispatch the initial REQUEST_VIDEOS action, as the LIST action is intrinsically used instead.

The next thing to notice is how category is retrieved from Redux state, rather than ownProps.match.params.category which only exists in the View Layer.

The last and perhaps most important thing to observe is how the new way uses a stateless component, while the old way requires both componentDidMount and componentWillReceiveProps to truly get the job done:

after looking at RFR’s route-centric approach, it barely makes sense to update your store from components anymore (unless it’s onClick/etc)

Redux-First Router automates this and re-calls your thunk as the user navigates from category to category, i.e. from URL to URL. When it comes to server-rendering, RFR really shines — you no longer need to discover which components have data dependencies; the router will resolve all thunks and prepopulate your store for you, before your . We’ll tackle SSR with RFR in depth in a future article.

As for the videos themselves, they both share the same primary reducer for storing videos by category:

However their loading reducers are slightly different

old loading reducer

Notice the RFR loading reducer responds to the innate LIST type you never had to dispatch, and how match.params.category has moved out of the to its own simple reducer:

new loading reducer + category reducer

Aside from contextual application of thunks, the most important improvement is actually the simplicity of receiving types and payloads corresponding to routes, as you can see in the screenshot directly above.

To give this some perspective, here’s a quote from the readme:

“You should not read the location state directly from the Redux store. This is because React Router operates asynchronously (to handle things such as dynamically-loaded components) and your component tree may not yet be updated in sync with your Redux state. You should rely on the props passed by React Router, as they are only updated after it has processed all asynchronous code.”

So in short, using React Router, you’re stuck with state in the view layer (and you already know what we think about that). Whereas with Redux-First Router, you can deal with URL state like any other state, and in a natural way. Might I say .


Redux-First Router gives your thunks context based on the URL, and by doing so reduces the number of action creators you need while self-documenting their purpose.

RFR brings into focus the core data-fetching work of your action by removing the need to perform URL/history-related chores and by performing the setup dispatch for you.

RFR forces you to write better, fatter, smarter reducers.

RFR eliminates the “state in the view layer” trap, as well as the aforementioned problems React Router has with syncing to Redux.

RFR’s configuration contract puts the breaks on exploding usage of middleware + thunks by providing you with a familiar yet Redux-specific interface that lends itself to “thin controllers.”

RFR nevertheless works with existing middleware and Apollo.

RFR makes server-rendering a first-class priority that won’t bite you in the butt when it comes time to address it. Code-splitting is equally straightforward.

Redux-First Router uses Redux terminology and idioms and is an excellent impedance match to Redux.

If you haven’t tinkered with it yet, you can do so right here. Here’s the routesMap.js file that has been the focus of today’s analysis:

UPDATE (July 23rd): Reselect has been implemented for the isLoading indicator and the videosByCategory reducer simplified by breaking it into an additional reducer: category. So this article won’t reflect exactly what’s in the CodeSandbox, but it will be a good learning transition, as I didn’t initially want to introduce Reselect.


The React Stack: Idiomatic Javascript in Reactlandia


The React Stack: Idiomatic Javascript in Reactlandia

James Gillmore

Written by +


The React Stack: Idiomatic Javascript in Reactlandia