DEV Community

Cover image for The future of Reach Router and React Router
Brian Neville-O'Neill
Brian Neville-O'Neill

Posted on • Originally published at blog.logrocket.com on

The future of Reach Router and React Router

Written by Yusuff Faruq✏️

In May of 2019, Ryan Florence, co-creator of React Router and Reach Router, announced the impending release of a new version of React Router that takes advantage of React’s Hooks API. He also stated that React Router would be the surviving project, while Reach Router will continue to receive support in the form of bug fixes.

Fast-forward to September 2019, and React Router v5.1 was eventually released. This version is an introduction to the new Hooks-based API and comes with some amazing features. The new Hooks also make routing easier.

In this article, I will talk about the new features in React Router, compare Reach Router (and React Router) to the new Hooks-based API, and briefly discuss how to migrate to this API.

LogRocket Free Trial Banner

The Hooks

The useHistory Hook

A new addition to React Router is the useHistory Hook, which gives you access to the “history” instance from the history package, one of React Router’s major dependencies. The history object allows for programmatic navigation between routes in your React apps.

In React Router v4, to access the history object, you had to use the history prop.

Let’s say we wanted to programmatically navigate to a route called home using a button. With React Router v4, our code would look similar to this:

function HomeButton({history}) {
  function handleClick() {
    history.push("/home");
  }
  return (
    <button type="button" onClick={handleClick}>
      Go home
    </button>
  );
}
Enter fullscreen mode Exit fullscreen mode

However, with the introduction of the useHistory Hook, we can easily access the history object and use it like so:

import { useHistory } from "react-router-dom";

function HomeButton() {
  const history = useHistory();
  function handleClick() {
    history.push("/home");
  }
  return (
    <button type="button" onClick={handleClick}>
      Go home
    </button>
  );
}
Enter fullscreen mode Exit fullscreen mode

If the user clicks on the button, the home entry will be pushed onto the history stack, and the home page will be rendered.

The useLocation Hook

The next Hook we will discuss is useLocation. This Hook returns the location object, which represents the current URL. The location object can also be used to access data sent from another route using the location object’s state property.

In React Router v4 and Reach Router, to gain access to the location object, you had to access them using props or, in the case of Reach Router, a Location component.

This is how you would access the location object with React Router v4:

function RandomRoute({ location }) {
  return <h1>Current pathname: {location.pathname}</h1>;
}
Enter fullscreen mode Exit fullscreen mode

And this is how you would access the location object in Reach Router:

function RandomRoute() {
  return (
    <Location>
      {({ location }) => <h1>Current pathname: {location.pathname}</h1>}
    </Location>
  );
}
Enter fullscreen mode Exit fullscreen mode

Now, with the new useLocation Hook, you can access the location object more conveniently, like so:

function RandomRoute() {
  const location = useLocation();
  return <h1>Current pathname: {location.pathname}</h1>;
}
Enter fullscreen mode Exit fullscreen mode

The useParams Hook

React Router v5.1 also gives us the new useParams Hook. This Hook returns an object of key-value pairs of URL parameters. URL parameters, commonly used among React Router and Reach Router users, allow us to conveniently pass information about a click through a URL.

In Reach Router and previous versions of React Router, the only way we could access URL parameters was through props and, in the case of Reach Router, the Match component.

So, with React Router v4, we would have to do something like this:

import {
  BrowserRouter as Router,
  Switch,
  Route,
  Link
} from "react-router-dom";
function App() {
  return (
    <Router>
      <header>
        <nav>
          <Link to="/">Home</Link>
          <Link to = "/page/2">Page 2</Link>
        </nav>
      </header>
      <Switch>
        <Route path = "/page/:pageNumber" component = {Page}>
        <Route path="/" render={() => <h1>Home</h1>} />
      </Switch>
    </Router>
  );
}
function Page({match}) {
  const {pageNumber} = match.params;
  return <h1>Page Number:{pageNumber}</h1>;
}
Enter fullscreen mode Exit fullscreen mode

Or something like this, in the case of Reach Router:

import { Router, Link } from "@reach/router";
function App() {
  return (
    <>
      <header>
        <nav>
          <Link to="/">Home</Link>
          <Link to="/page/2">Page 2</Link>
        </nav>
      </header>
      <Router>
        <Home path="/" />
        <Page path="/page/:pageNumber" />
      </Router>
    </>
  );
}
const Home = () => <h1>Home</h1>;
function Page(props) {
  return <h1>Page Number:{props.pageNumber}</h1>;
}
Enter fullscreen mode Exit fullscreen mode

The above methods work fine for most cases. But if you are trying to pass URL parameters down to child components, you would have to pass them them as props, which can make your code messy.

With the new Hooks API, you can easily call the useParams Hook in any child component to get the URL parameters. If we were to rewrite our code to use Hooks, it would look something like this:

import {
  BrowserRouter as Router,
  Switch,
  Route,
  Link,
  useParams
} from "react-router-dom";
function App() {
  return (
    <Router>
      <header>
        <nav>
          <Link to="/">Home</Link>
          <Link to = "/page/2">Page 2</Link>
        </nav>
      </header>
      <Switch>
        <Route path = "/page/:pageNumber">
          <Page />
        </Route>
        <Route path="/" render={() => <h1>Home</h1>} />
      </Switch>
    </Router>
  );
}
function Page() {
  const {pageNumber} = useParams();
  return <h1>Page Number:{pageNumber}</h1>;
}
Enter fullscreen mode Exit fullscreen mode

The useRouteMatch Hook

The last new Hook is useRouteMatch. In Reach Router, if you wanted to access the match object of a Route, you would have to use the Match component. And if you were using a previous version of React Router, you would have to use the route’s props or render props. With this new Hook, it’s easier and more convenient to access match object!

The Hook takes in a path as an argument and returns a corresponding match object. When no argument is passed, the Hook returns a match object based on the closest matching <Route> in the tree.

Former way of accessing a match object in React Router:

//option 1
function ARoute() {
  return (
    <Route
      path="/randomroute/:randomrouteid"
      render={({ match }) => {
        return (
          ...
        );
      }}
    />
  );
}

//option 2
function ARoute(props){
  const match = props.match;
  return (
    ...
  );
}
Enter fullscreen mode Exit fullscreen mode

To get the match object in Reach Router, we would have to use the provided Match component:

function AnotherRandomRoute(){
    return(
        <Match path = "/randomroute/:randomrouteid">
            {
                ({match}) => ...
            }
        </Match>
    );
}
Enter fullscreen mode Exit fullscreen mode

The above code blocks work fine, but we can make our code shorter and cleaner with the useRouteMatch Hook, like so:

function AnotherRandomRoute(){
    const match = useRouteMatch("/randomroute/:randomrouteid");
    return(
        ...
    );
}
Enter fullscreen mode Exit fullscreen mode

With useRouteMatch, you can also implement nested routing using the url and path properties of the match object. Here’s an example of how you might handle nested routing in React Router with this Hook:

function Topics() {
  const { path, url } = useRouteMatch();
  return (
    <div>
      <div>
        <Link to={`${url}/1`}>Topic 1</Link>
        <Link to={`${url}/2`}>Topic 2</Link>
        <Switch>
          <Route exact path={path} render={() => <h1>Select a topic</h1>} />
          <Route path={`${path}/:topic`}>
            <Topic />
          </Route>
        </Switch>
      </div>
    </div>
  );
}
function Topic() {
  const { topic } = useParams();
  return (
    <div>
      <h1>Topic: {topic}</h1>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

useRouteMatch is also useful any time you would use a Route component outside a Switch component.

Updates to the Link and NavLink components

React Router v5.1 also added some updates to the Link and NavLink components, one of which is the ability to pass in functions to these components’ to props. The current location is passed as an argument to the function, and this function must return a location representation in the form of an object or a string.

React Router v6

Currently, a major version of React Router is in the works. React Router v6, which is currently in the alpha stage, will have the following features:

  • A smaller bundle size. The current size of the new version in a fully migrated app is around 3kB. According to a tweet by Michael Jackson, co-creator of React Router, they were able to achieve this by dropping support for anything older than IE11, dropping support for React <16.8, using Google Closure Compiler, and writing better code
  • Automatic <Route> ranking with a new <Routes> API. <Routes> will replace <Switch>
  • Nested route configs (much like React Router v3 and Reach Router)
  • New Suspense-ready navigate API
  • useRoutes and matchRoutes for using object-based routing API
  • A new Hook called useNavigate, which returns a function for programmatic routing/navigation.

Migrating from Reach Router to the new Hooks-based API

If you are planning to migrate from Reach Router, it’s easier to migrate to React Router v6 because they look similar at surface level. You can easily migrate by following these steps:

  • Install React Router v6
  • Replace <Location> and <Match> with the useLocation and useRouteMatch Hooks
  • Use useParams to access URL parameters
  • Put a <BrowserRouter> on top:
ReactDOM.render(
  <BrowserRouter>
    <App />
  </BrowserRouter>,
  document.getElementById("root")
);
Enter fullscreen mode Exit fullscreen mode
  • Replace <Router> with <Routes> and define your routes using <Route>

Conclusion

So far, React Router v6 is looking very promising. The new features and Hooks will definitely encourage cleaner code, and I think it was a great decision on the part of the React Router team to move towards building a Hooks-based API.


Full visibility into production React apps

Debugging React applications can be difficult, especially when users experience issues that are difficult to reproduce. If you’re interested in monitoring and tracking Redux state, automatically surfacing JavaScript errors, and tracking slow network requests and component load time, try LogRocket.

Alt Text

LogRocket is like a DVR for web apps, recording literally everything that happens on your React app. Instead of guessing why problems happen, you can aggregate and report on what state your application was in when an issue occurred. LogRocket also monitors your app's performance, reporting with metrics like client CPU load, client memory usage, and more.

The LogRocket Redux middleware package adds an extra layer of visibility into your user sessions. LogRocket logs all actions and state from your Redux stores.

Modernize how you debug your React apps — start monitoring for free.


The post The future of Reach Router and React Router appeared first on LogRocket Blog.

Top comments (0)