In Development Last updated:
Share on:
Jira Software is the #1 project management tool used by agile teams to plan, track, release, and support great software.

For any non-trivial React application, you must break it down into multiple pages. To do so, it becomes necessary to implement react routing.

This can be an intimidating topic at first. However, this tutorial will get you up to speed with all the necessary fundamentals. In this tutorial, we will be building an app that uses routing.

What is React Routing (Client-side Routing)

React routing is a form of client-side routing implemented in React applications. Client-side routing is an alternative to server-side routing. In server-side routing, the browser makes a GET request to the web server whenever you navigate to a different page. This request could take a few seconds before you get a response.

For a web application where you are constantly moving between pages, the wait time creates a bad user experience. Client-side routing is an alternative to this. Instead of providing the browser with HTML, the app uses JavaScript to generate the HTML for different pages.

You only need to provide an index.html file as an entry point for your app to work. This entry point then loads your JavaScript code. The JavaScript bundle will render pages by manipulating the DOM, handling routing, and implementing app functionality.

Because the server only renders the index.html page, the application is called a single-page application.

Advantages of Client-side Routing

  • It creates a better user experience as the navigation is faster, and the application will be more responsive. With server-side routing, every navigation is a network request with a few seconds of latency.
  • It enables the creation of offline applications as all the code required to run the app can be cached locally. This allows you to build more available applications and offer offline functionality.
  • The application will also use less data as network requests significantly reduce if everything is sent once and some files are cached locally.
  • It also reduces server load as the server only has to render the application once. This contrasts with server-side rendering, where the server continually renders the application.

Next, let’s discuss how to implement react routing.

How to Implement React Routing

For this tutorial, we will be building a simple note-taking application. It will be made up of multiple pages. We will implement client-side routing using React Router DOM to enable the client to navigate between the different pages. We will not be building everything for the app to work. Instead, we will focus on routing.

Prerequisites

To follow this tutorial, you must understand HTML, JavaScript, and React. You will also need to have Node.js and NPM installed. You can download and install them simultaneously by installing Nodejs from the website. Or follow the guide in the YouTube video embedded.

What We Are Building

The app will have multiple pages. Using react routing, you will be able to navigate to different pages. The designs for the pages are shown below.

The Home page is rendered at the ‘/’ route.

The About page is rendered at the ‘/about’ route.

Notes Page at the ‘/notes’ route.

New Note Page at the ‘/notes/new’ route.

You can see each note in full on the Note Page. This page is rendered at the ‘/routes/<id>’ route, where the <id> is an integer representing the id of the note we want to read.

Getting Started

To get started, create a new React project. I am going to be using Vite, so the command to initialize a new project is this:

npm create vite@latest scribbble --template react

I specified ‘scribbble’ as the project name and React as the template. Next, I am going to open VS Code using the commands below:

cd scribbble
code .

After VS Code is open, I will return to the terminal window and install react-router-dom. This package makes it easier to implement react routing in your applications.

npm install react-router-dom

We are going to create a file where our notes are going to be stored. Create a src/notes.js file and add the following code:

const notes = [
  {
    id: 1,
    title: "Note 1",
    body: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.",
  },
  {
    id: 2,
    title: "Note 2",
    body: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.",
  },
  {
    id: 3,
    title: "Note 3",
    body: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.",
  },
];

export default notes;

Next, delete the src/App.css file. We won’t be using it in this project. Also, make sure to remove the import for the App.css file from the App.jsx file.

After that, replace everything in the index.css file with this:

:root{font-family:Inter,system-ui,Avenir,Helvetica,Arial,sans-serif;font-weight:400;color:#404040}*{margin:0;padding:0}.nav-container{display:flex;justify-content:space-between;padding:15px 30px}.home-buttons,.nav{display:flex;gap:10px}a{text-decoration:none;color:inherit;font-weight:600}h1{font-size:63px;margin:20px 0}input,textarea{border:1px solid #f1f1f1;background-color:#fafafa;outline:0;padding:10px;width:100%}textarea{resize:none;font-family:inherit}.container{padding:15px}.primary{background-color:#8a2be2;color:#fff}.secondary{background-color:#eee}.button{padding:15px 30px;font-size:16px;border:none;font-weight:700;border-radius:7px;cursor:pointer}.home-container{height:300px;display:flex;flex-direction:column;align-items:center;justify-content:center}.new-note-container{padding:20px}.new-note-form{display:flex;flex-direction:column;align-items:center;width:500px;gap:20px;margin:auto;border-radius:7px;padding:20px 30px}.notes-list{display:grid;grid-template-columns:1fr 1fr 1fr;gap:30px;padding:0 60px}.note{border:1px solid #d3d3d3;padding:15px;border-radius:7px}.note h2{font-size:1rem;margin-bottom:10px}.note p{color:#585858;font-size:.9rem;cursor:pointer}.note-container{display:flex;align-items:center;justify-content:center;padding:50px}.note-content{width:500px}

Next, create the following files for the pages we are going to be creating:

  • src/pages/Home.jsx
  • src/pages/About.jsx
  • src/pages/Note.jsx
  • src/pages/NewNote.jsx
  • src/pages/Notes.jsx

Then, create the file for the Navigation Bar component. This file will be located at src/components/NavBar.jsx

Setting Up React Routing

With our app set up, we will set up routing in our application next.

Open the App.jsx file and delete everything inside. Next, add the following imports to the top of the file:

import { BrowserRouter, Routes, Route } from "react-router-dom";
import { NavBar } from "./components/NavBar";
import { Home } from "./pages/Home";
import { About } from "./pages/About";
import { Notes } from "./pages/Notes";
import { Note } from "./pages/Note";
import { NewNote } from "./pages/NewNote";

We are importing the BrowserRouter, Routes, and Routes components from react-router-dom. These will be used to set up a router. Next, we imported the NavBar from our components directory and several pages from our pages files. We haven’t implemented the pages yet, but we will soon.

Next, we are going to set up our App component:

export default App () {

}

Then, we add the following markup within our return statement:

return (
    <BrowserRouter>
      
    </BrowserRouter>
)

This renders the BrowserRouter, a React component provided by the react-router-dom component. This component configures a router that works within the browser. Our app will be contained inside those tags.

Next, we will add the navigation bar and create a Routes component.

return (
    <BrowserRouter>
      <NavBar />
      <div className="container">
        <Routes>
          
        </Routes>
      </div>
    </BrowserRouter>
  );

Inside the BrowserRouter element, we added a NavBar. We will define this element later, but it creates the links at the top of each page. Instead of writing it separately for each page, we will create one NavBar.

Then, we created a container element. This element is not necessary for routing. We just added it to apply styling.

Inside the container, we added the Routes component. This is where different pages will be rendered depending on the route the browser is on. Everything inside the Routes component will be re-rendered every time the route changes.

Lastly, we add the routes for the different pages.

  return (
    <BrowserRouter>
      <NavBar />
      <div className="container">
        <Routes>
          <Route path="/" Component={Home} />
          <Route path="about" Component={About} />
          <Route path="notes" Component={Notes}>
            <Route path="new" Component={NewNote} />
            <Route path=":id" Component={Note} />
          </Route>
        </Routes>
      </div>
    </BrowserRouter>
  );

The Home component will be rendered when the path is ‘/’, and the About component will be rendered on the ‘/about’ route. The Notes component will be rendered at the ‘/notes’ route. We also have the ‘/notes/new’ route and ‘/notes/:id’ defined as nested routes.

Nested Routes Explained

A route can contain inner routes. These are called nested routes. The path to these nested routes will be joined to the parent route to form the complete path. For example, the ‘notes’ and ‘new’ routes will be combined to ‘/notes/new’.

As for how the components are rendered when the user navigates to the parent route, only the parent component will be rendered. However, the parent and nested components will be rendered together when they navigate the nested route.

To render both components together, the Notes component must render an Outlet component that specifies where the Note component will be embedded. You will see this later when we start creating the Pages.

Dynamic Routes

So far, we have been specifying the literal route we want to match. For example, the ‘/’ and ‘about’ routes. However, react-router-dom enables us to specify dynamic routes. A dynamic route contains a portion that can be matched against a query parameter. When matched, the query parameter is passed on to the page.

For example, inside the ‘posts’ parent route, we have a nested route that contains a dynamic portion specified by :id. This route accepts any text in place of :id , and that text becomes available to the Note component as id.

Building the Navigation Bar

We use Link components instead of normal anchor tags to navigate using react-router-dom. Therefore, our navigation bar should look like this:

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

export function NavBar() {
  return (
    <div className="nav-container">
      <Link to="/">Scribbble</Link>
      <nav className="nav">
        <Link to="/about">About</Link>
        <Link to="/notes">Notes</Link>
        <Link to="/notes/new">New Note</Link>
      </nav>
    </div>
  );
}

Add the code to src/pages/NavBar.jsx.

Building Out the Pages

Next, we are going to build the pages. For the Home Page, add the following code to the src/pages/Home.jsx.

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

export function Home() {
  const navigate = useNavigate();

  return (
    <div className="home-container">
      <h1>Notes for professionals</h1>
      <div className="home-buttons">
        <button
          onClick={() => {
            navigate("/notes/new");
          }}
          className="button primary"
        >
          Start Scribbling
        </button>
        <button
          onClick={() => {
            navigate("/notes");
          }}
          className="button secondary"
        >
          View Notes
        </button>
      </div>
    </div>
  );
}

In the HomePage, we would like to use buttons to navigate. As a result, we use the useNavigate hook to navigate programmatically. We imported the hook and then called it inside the Home Component. The return value after calling the hook is a function you can use to navigate.

Next, we will define the About page. Add the following code to your src/pages/About.jsx file.

export function About() {
  return (
    <div>
      <h1>About</h1>
      <p>Simple Notes is the best note-taking application for professionals</p>
    </div>
  );
}

After this, we will define the Notes page.

In this component, we also have to include an Outlet component that will be used to render any nested routes. For this reason, our src/pages/Notes.jsx page will look like this.

import { Outlet, useNavigate } from "react-router-dom";
import notes from "../notes";

export function Notes() {
  const navigate = useNavigate();
  return (
    <div>
      <Outlet />
      <div className="notes-list">
        {notes.map((note) => {
          return (
            <div
              className="note"
              key={note.id}
              onClick={() => {
                navigate("/notes/" + note.id);
              }}
            >
              <h2>{note.title}</h2>
              <p>{note.body.slice(0, 100)}</p>
            </div>
          );
        })}
      </div>
    </div>
  );
}

Next, we define the Note page.

This will be rendered for an individual note. To decide on a note to render, Notes will access the id specified in the dynamic portion of the route. To do so, we use the userParams hook. Therefore, this should be code inside your src/pages/Note.jsx file:

import { useParams } from "react-router-dom";
import notes from "../notes";

export function Note() {
  const params = useParams();
  const note = notes.find((note) => note.id == params.id);
  return (
    <div className="note-container">
      <div className="note-content">
        <h2>{note.title}</h2>
        <p>{note.body}</p>
      </div>
    </div>
  );
}

Lastly, we will create the NewNote component inside the src/pages/NewNote.jsx using the following code:

export function NewNote() {
  return (
    <div class="new-note-container">
      <form class="new-note-form">
        <h2>New Note</h2>
        <input type="text" name="title" placeholder="Note title" />
        <textarea rows="10" placeholder="Note text" />
        <button class="button primary">Save Note</button>
      </form>
    </div>
  );
}

At this point, we have written all the code for the application. You can run the app using npm run dev. Navigate to different pages and see how fast client-sider-routing is.

Disadvantages of Client-side Routing

Despite its many advantages, client-side routing has several disadvantages. These are explained below:

  • The initial page load can be slow as the entire app has to be loaded. The JavaScript bundle can be very large, requiring long load times.
  • Because JavaScript generates the markup, the page will not be SEO-optimised.
  • Because everything relies on JavaScript, browsers that do not support JavaScript or that have JavaScript disabled will not be able to run the application.

Conclusion

In this article, we covered react routing by building a small project. While we didn’t cover everything, this tutorial covers concepts you will use in most of the projects you will work on. For more information on react-router-dom, here are the official docs.

Next, read this article on React form libraries.

Share on:
  • Anesu Kafesu
    Author
    I am a Software Engineer specialising in Web Development, Mobile Application Development and Artificial Intelligence. I occasionally write on the same topics.
  • Rashmi Sharma
    Editor

    Rashmi is a highly experienced content manager, SEO specialist, and data analyst with over 7 years of expertise. She has a solid academic background in computer applications and a keen interest in data analysis.


    Rashmi is…

Thanks to our Sponsors

More great readings on Development

Power Your Business

Some of the tools and services to help your business grow.
  • The text-to-speech tool that uses AI to generate realistic human-like voices.

    Try Murf AI
  • Web scraping, residential proxy, proxy manager, web unlocker, search engine crawler, and all you need to collect web data.

    Try Brightdata
  • Monday.com is an all-in-one work OS to help you manage projects, tasks, work, sales, CRM, operations, workflows, and more.

    Try Monday
  • Intruder is an online vulnerability scanner that finds cyber security weaknesses in your infrastructure, to avoid costly data breaches.

    Try Intruder