Tutorial

How To Compare React Router and Reach Router

React
This tutorial is out of date and no longer maintained.

Introduction

Reach Router is authored by Ryan Florence. If you recognize his name it’s because he’s the original co-author of React Router, which is currently the most popular routing library.

Both libraries appear to have identical purposes to provide a routing layer for the web. However, Reach Router is taking a fresh approach to the solution, and it also comes with accessibility (a11y) baked-in and working out of the box.

Warning: Since the original publication, it has been announced that React Router will adopt many of the features of Reach Router. You should consult the “Which Project Should I Choose Today?” section for your project’s needs.

In this article, you will compare React Router to Reach Router in order to better understand what each library supports and provides.

Prerequisites

To follow along with this tutorial, you will need:

Comparing Set Up

Reach Router is very similar to React Router and uses similar namespaces like <Router>, <Link>, etc., but there are some noteworthy differences. Let’s consider a basic setup for both react-router and reach-router.

First, a setup using React Router:

React Router
import React from "react"; import { BrowserRouter as Router, Route } from "react-router-dom"; const App = () => { return ( <Router> <div> <h1>Global Party Supplies, Inc</h1> // PATHS <Route component={Home} path="/" exact/> // "/" <Route component={About} path="/about"/> // "/about" <Route component={Support} path="/support"/> // "/support" <Route component={Dashboard} path="/dashboard"/> // "/dashboard" <Route component={Invoices} path="/dashboard/invoices"/> // "/dashboard/invoices" <Route component={Team} path="/dashboard/team"/> // "/dashboard/team" <Route component={Report} path="/dashboard/:reportId"/> // "/dashboard/:reportId" </div> </Router> ); }

React Router has its own <Route> component that takes two props: component and path.

Here’s the same setup using Reach Router:

Reach Router
import React from "react"; import { Router } from "@reach/router"; const App = () => { return ( <div> <h1>Global Party Supplies, Inc</h1> <Router> // PATHS <Home path="/"/> // "/" <About path="about"/> // "/about" <Support path="support"/> // "/support" <Dashboard path="dashboard"> // "/dashboard" <Report path=":reportId"/> // "/dashboard/:reportId" <Invoices path="invoices"/> // "/dashboard/invoices" <Team path="team"/> // "/dashboard/team" </Dashboard> </Router> </div> ); }

The first impression is that this looks really clean. Reach Router doesn’t have a <Route> component. You just use the component itself (e.g., <Dashboard>)! Using nested JSX for subpaths (/dashboard/team) distinguishes itself from React Router.

But wait… there’s something weird here. At first glance you may think the <Report> route would intercept /dashboard/invoices and /dashboard/team, but it actually doesn’t!

Reach Router uses a point system to rank your route definitions by looking at the path value. When two paths seem to collide, params (:reportId) and wildcard (*) get low-priority, while explicit paths (invoices and teams) get higher priority. This means navigating to /dashboard/invoices actually works, and /dashboard/example goes to <Report>.

Comparing Params and Props

Now that we’ve explored the basic setup, let’s explore how you would pass data to routes.

First, reportId and salesData with React Router:

React Router
<Route path="/dashboard/:reportId" render={(props) => { return <Report {...props} salesData={true} /> }} /> const Report = ({ props, match }) => { return ( <h1> {match.params.reportId} // "match" is from react-router and {props.salesData} </h1> ) }

There’s more stuff involved with React Router, but this is normal fare if you’ve been using it for any amount of time.

Here’s the same example with Reach Router:

Reach Router
<Report path="dashboard/:reportId" // static routes work too :) salesData={this.state.salesData} /> const Report = (props) => { return ( <h1> {props.reportId} and {props.salesData} </h1> ) }

Note how reportId does not require match to access the URL parameters.

Next, let’s investigate how <Link>ing works in both libraries.

Comparing Linking

Both Reach Router and React Router export a <Link> component, but there are some differences. Let’s consider a <Dashboard> component which has several subpages.

First, with React Router:

React Router
import { Link } from "react-router-dom"; const Dashboard = ({ match, history }) => { return ( <div> <div> <Link to={`${match.url}/invoices`}>Invoices</Link> <Link to={`${match.url}/team`}>Team</Link> </div> <!-- content --> <div> <Link to="/">Home</Link> <Link to="/about">About</Link> <Link to="/support">Support</Link> <a onClick={history.goBack}>Go Back</a> </div> </div> ); }

With React Router you have to be specific with <Link> which usually means you’ll have to use match.url when you have subpaths beyond a root subpath (e.g., /host/path1/path2). Also, note that you have to programmatically goBack since there isn’t a utility for relative navigation.

Here’s the same example with Reach Router:

Reach Router
import { Link } from "@reach/router"; const Dashboard = () => { return ( <div> <div> <Link to="invoices">Invoices</Link> <Link to="team">Team</Link> </div> <!-- content --> <div> <Link to="/">Home</Link> <Link to="/about">About</Link> <Link to="/support">Support</Link> <Link to="../">Go Back</Link> </div> </div> ) }

Reach Router supports relative links! It also fully supports Unix directory navigation like <a> tags would.

Conclusion

In this article, you compared React Router to Reach Router in order to better understand what each library supports and provides.

Based on these comparisons, Reach Router is a very tempting alternative to React Router. Overall, it’s more elegant in conveying information when reading and writing the code. This shouldn’t come as a surprise as Ryan Florence is the co-author of react-router, and most hard-fought insights can only be gotten through time and experience.

Give Reach Router a try! The first v1.0 release was in May 2018 and GatsbyJS v2 has already opted for Reach Router against React Router.

Creative Commons License