Last updated 1 year ago by bgdam bgdamreact
React-Router is the most popular routing solution out there for React applications — so much so, that a lot of developers think of it as the ‘Official Routing Solution’ for React. While I’m sure React-Router works quite well for a lot of people, I’ve always disliked working with React-Router. I’ll try to summarize my reasons in this article.
React-Router is arguably the most popular routing solution for writing React applications today. Most frontend developers these days automatically include Redux, React-Redux and React-Router as de-facto dependencies for pretty much any application. Including Redux, is something I can understand, as it provides quite a few tangible benefits, but what I don’t understand is why anybody would settle for a routing solution that is both inferior and needlessly complicated.
For a bit of background, let me say that while I’ve been working across the stack for the past 12 years, my primary preference has always been to work on the backend, or on non-browser front ends. I used to absolutely loathe writing front-end code for browsers, because it was too messy, and inevitably devolved into a huge mess of spaghetti code. Thankfully, the last few years, tooling for the front-end has improved tremendously and most of my pain points have been resolved. I started actively writing browser front-end code, when I first started learning React, some three+ years ago.
So as a guy who has done a lot of backend work, on both APIs and web apps returning rendered HTML pages, using everything from php running on cgi-bin (with paths to files mapped as urls), to Express and Koa, with well-defined explicit routing. I’ve got a very specific idea of what a router is, what it should do, and how it should do it. To me, a
Router is a piece of glue code that uses the requested url to identify a
Controller, and execute that controller, providing it with a certain
context, which usually contains information about the incoming request. That's it. Nothing more.
If you look into Express.JS’s router, you’ll see that is exactly what it does. It exposes an API, that allows you to register controllers to routes (and methods), and then when a request is received for any of the registered routes, it executes the registered controllers in the order they were registered in. It exposes a very simple API that nevertheless packs in a lot of flexibility and functionality into it. This is my gold standard for a router. It does one thing, it does it well, and it stays out of your way at all other times.
So let’s jump into what I don’t like about React-Router and why.
My view of components has always been that they are part of the view layer, and when I write applications, I work to keep business logic like API calls, validation, etc. out of the actual component, and instead try to keep them at the controller level.
However, React-Router’s ‘everything is a component’ approach to routing makes this impossible. Say I want to fetch some data from my backend before rendering a component, the solution to this in React-Router land is to create a new custom component which will ‘block’ the navigation until the data is made available.
According to React-Router docs, there are three types of components in React-Router, only one type of which (
Link) is actually a view component. The rest are there to enable routing. Why is my router play acting as React components?
React-Router exposes two different routers,
StaticRouter. If you need to make a few API requests to fetch data before rendering, then the way to achieve this differs significantly based on which router you're using. Pretty much all examples I've seen for server side rendering with React-Router, show significant differences in the server routing code, and in the browser routing code. This limits the amount of code that could possibly be reused between the server and the client.
On the server side, you actually have to use
matchPath an internal method used by the router, to manually check if the path matches the path of the incoming request, and then call the associated helper function to make the API call and get the data. Hang on a minute! Isn't matching a path and calling the registered controller literally the definition of a router? So to perform server side rendering with async data fetching using React-Router, you have to write your own mini-router inside the