Programmatically Navigate Using React Router

Introduction

Pages on modern websites, and especially Single-Page Applications (SPAs) do not follow the traditional method of loading new pages completely whenever something changes on them. Client-Side Routing is used instead - to route towards resources to load another part of the program or structurally change the application's entire view if needed, when an action (such as clicking a button or link) is performed.

React is a massively popular library for front-end development used to create highly responsive user interfaces, and naturally, it has its own Router, which performs Client-Side Routing - the react-router-dom.

In this guide, we'll take a look at how to create routes in a React application, programmatically navigate between routes, as well as send and retrieve data between them, using React Router.

Creating a React Application

Let's start out by creating a simple React application via the command line:

$ npx create-react-app router-sample

Once created, let's move into the project's directory, and start the application:

$ cd router-sample
$ npm start

This will start up a server on localhost:3000 and your default browser will fire up to serve the application. Before creating any new files to serve on this endpoint, let's install react-router-dom, since it doesn't come prepackaged.

Installing React Router

As usual, installing a package using npm is as simple as running a single command:

$ npm install react-router-dom

Creating New Routes with React Router

The react-router-dom package makes it simple to create new routes. To begin, you wrap the entire application with the <BrowserRouter> tag. We do this to gain access to the browser's history object. Then you define your router links, as well as the components that will be used for each route.

To demonstrate this, let's create a new file called About.js in the /src folder:

const About = () => {
  return (
    <div>
      <h1>About page here!</h1>
      <p>
        Lorem ipsum dolor sit amet consectetur adipisicing elit. Fugit, modi!
      </p>
    </div>
  );
};

export default About;

Now, let's update the src/index.js page and import About from the file we've just created. Within the <BrowserRouter> tag, we'll define our routes and components associated with them:

import { render } from "react-dom";
import { BrowserRouter, Routes, Route } from "react-router-dom";
import App from "./App";
import About from "./About";

render(
  <BrowserRouter>
    <Routes>
      <Route path="/" element={<App />} />
      <Route path="about" element={<About />} />
    </Routes>
  </BrowserRouter>,
  document.getElementById("root")
);

We've imported the <BrowserRouter> here, and we've wrapped our entire application around it. We'd also selected App.js as the component for our home page (under the / endpoint), and About.js as the component for the /about page.

Finally, let's adapt the App.js file, which will, again, be the main entry point for the application and serve our home page:

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

function App() {
  return (
    <div className="App">
      <h1>Welcome to my react app!</h1>
      <p>
        Lorem ipsum dolor sit amet consectetur adipisicing elit. Accusamus,
        pariatur?
      </p>
      <br />
      <Link to="/about">About Page</Link>
    </div>
  );
}

export default App;

At this stage, we've created two routes: the entry route (/) and the /about route, and we should be able to easily navigate from the home page to the about page when we visit our application:

React Router Hooks (Navigation Methods)

Hooks were added to React recently, which are functions that allow you to "hook" into the application's state, without having to write new classes. The React Router comes with a few hooks that allow us to programmatically access the Router State and navigate between components. Among these are the following hooks:

  • useHistory()
  • userNavigate()
  • useLocation()
  • useParams()

To use any of these hooks, we must first import them from the react-router-dom package and then specify a variable that invokes the hook; we'll go through this in more detail in the sections that follow.

useHistory()

Note: The useHistory() hook has been deprecated in the latest version of React Router. If you're using React Router V6, you'll want to use the useNavigate() hook instead. It's covered right after useHistory().

The useHistory() hook provides direct access to React Router's history instances, enabling us to perform actions like retrieving the number of entries in the history stack, adding, altering, or removing an entry from the stack, and so on.

Free eBook: Git Essentials

Check out our hands-on, practical guide to learning Git, with best-practices, industry-accepted standards, and included cheat sheet. Stop Googling Git commands and actually learn it!

Some of the most useful methods here include:

  • goBack() - Go backward in history.
  • goForward() - Go forward in history.
  • push() - Add a new entry to the history stack, i.e., navigate to a new URL.
  • replace() - Similar to push() in that it replaces the current stack in the history, but unlike push(), the user cannot travel back in history, i.e. clicking the browser back button will not return to the previous state.

With just this, we can navigate from our About page to the home page programmatically, by push()-ing a new entry into the history, effectively navigating the user to the new entry:

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

const About = () => {
  let history = useHistory();

  const goHome = () => {
    history.push("/");
  };

  return (
    <div>
      <h1>About page here!</h1
      <p>
        Lorem ipsum dolor sit amet consectetur adipisicing elit. Fugit, modi!
      </p>
      <button onClick={goHome}>Go to home page</button>
    </div>
  );
};

export default About;

Here, we just import the useHistory() hook and create a new goHome() function that executes on a button click. It's just a wrapper for a push() call.

We can also transfer the state or send arbitrary data to the route we are navigating to. We can do this by sending an object to the push methods instead of the pathname as a string, and adding our state to a distinct object:

history.push({
  pathname: '/blog,
  search: '?blogId=12,  // Query string
  state: {              // Location state
    author_name: "John Doe", 
  },
}); 

After covering useNavigate(), we'll take a look at how to access this data using the useLocation() and useParams() hooks.

useNavigate()

If you're using the most recent version of React Router, the useHistory() hook has been deprecated in favor of useNavigate(). The approach is nearly identical; the main difference is that the useNavigate() hook does not accept methods like .push() or .replace(). You just navigate() to a certain entry:

import React from "react";
import { useNavigate } from "react-router-dom";

const About = () => {
  let navigate = useNavigate();

  const goHome = () => {
    navigate("/");
  };

  return (
    <div>
      <h1>About page here!</h1>
      <p>
        Lorem ipsum dolor sit amet consectetur adipisicing elit. Fugit, modi!
      </p>
      <button onClick={goHome}>Go to home page</button>
    </div>
  );
};

export default About;

And, of course, this method also allows us to transfer states between routes:

navigate("/blog", { state: { author_name: "John Doe" } });

Retrieving Data Between Routes with useLocation() and useParams()

The useLocation() hook provides us access to the browser's location object. Consider it the hook in charge of obtaining the necessary information about the current route:

import { useNavigate, useLocation } from "react-router-dom";
/*...*/
let location = useLocation();
console.log(location);

Running the code above should return all of the information about the current route, as shown below:

{
  "pathname": "/about",
  "search": "",
  "hash": "",
  "state": null,
  "key": "default"
}

It's reasonable to think of the useLocation() hook as a useState() hook that updates the state to a new location whenever the URL changes. On the other hand, the userParams() hook can be used to get the value of URL parameters. When called, useParams() provides an object that maps the names of URL parameters to their values in the current URL.

For example, in our router configuration, say we've had a dynamic route:

<Route path="/about/:user_id">
 <About />
</Route>

And on another page, we have a link component that points to some information pertaining to User 2:

<Link to="/about/2">About User 2</Link>

When parameters are passed, like we've seen before - we can access the parameters via the userParams() hook:

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

const About = () => {
  const { user_id } = useParams();

  return (
    <div>
      <h1>About user {user_id}</h1>
      <p>
        Lorem ipsum dolor...
      </p>
    </div>
  );
};

export default About;

Conclusion

React Router is used for Client-Side Routing of resources. In this guide, we've taken a quick look at how you can programmatically navigate an application using React Router as well as how to transfer states between routes when you do.

Last Updated: October 27th, 2023
Was this article helpful?

© 2013-2024 Stack Abuse. All rights reserved.

AboutDisclosurePrivacyTerms