React Router

Ndungu James KNdungu James K
7 min read

React Router is React's standard routing library. When you need to navigate through a React application with multiple views, you’ll need a router to manage the URLs. React Router does that while keeping your application's UI and URL in sync.

One of the main features of React is that it allows the creation of single-page applications (SPAs) that are rendered on the client's side. An SPA might have multiple views (aka pages), and unlike the conventional multi-page apps, navigating through these views should not result in the entire page being reloaded. Instead, we want the views to be rendered inline within the current page. The end user, who’s accustomed to multi-page apps, expects the following features to be present in an SPA:

Setting up React Router

Let's assume you already have a development environment up and running where you've used Create React App to generate the files required for creating a basic React project. The default directory structure generated by Create React App should look something like this:

react-routing-super-skill

├── README.md

├── node_modules

├── package.json

├── .gitignore

├── public

│   ├── favicon.ico

│   ├── index.html

│   ├── logo192.png

│   ├── logo512.png

│   ├── manifest.json

│   └── robots.txt

└── src

    ├── App.css

    ├── App.js

    ├── App.test.js

    ├── index.css

    ├── index.js

    ├── logo.svg

    └── serviceWorker.js

The React Router library comprises three packages: react-router, react-router-dom, and react-router-native. react-router is the core package for the router, whereas the other two are environment-specific. You should use react-router-dom if you’re building a website, and react-router-native if you’re on a mobile app development environment using React Native.

Let's use npm to install react-router-dom:

npm install --save react-router-dom

React Router Basics

Here’s an example of how our routes will look like:

<Routes>

         <Route path="/" element={<Home />} />

         <Route path="/category" element={<Category />} />

         <Route path="/login" element={<Login />} />

         <Route path="/products" element={<Products />} />

</Routes>

Router

You need a router component and several route components to set up a basic route as exemplified in the previous screen. Since we’re building a browser-based application, we can use two types of routers from the React Router API:

<BrowserRouter>

<HashRouter>

The primary difference between them is evident in the URLs that they create:

// <BrowserRouter>

http://example.com/about



// <HashRouter>

http://example.com/#/about

Router

The <BrowserRouter> is more popular amongst the two because it uses the HTML5 History API to keep track of your router history. The <HashRouter>, on the other hand, uses the hash portion of the URL (window.location.hash) to remember things. If you intend to support legacy browsers, you should stick with <HashRouter>.

Wrap the <BrowserRouter> component around the App component.

/* Import statements */

import React from 'react';

import ReactDOM from 'react-dom';

/* App is the entry point to the React code.*/

import App from './App';

/* import BrowserRouter from 'react-router-dom' */

import { BrowserRouter } from 'react-router-dom';
ReactDOM.render(

    <BrowserRouter>

        <App />

    </BrowserRouter>

    , document.getElementById('root'));

Note: A router component can only have one single child element. The child element can be an HTML element — such as div — or a react component.

For the React Router to work, you need to import the relevant API from the react-router-dom library. Here We’ve imported the BrowserRouter into index.js. We’ve also imported the App component from App.js. App.js, as you might have guessed, is the entry point to React components.
The above code creates a history instance for our entire App component.

Basic Routing

import {Routes, Route, Link } from "react-router-dom";

import "./styles.css";


/* Home component */

const Home = () => (

 <div>

   <h2>Home</h2>

 </div>

);

/* Category component */

const Category = () => (

 <div>

   <h2>Category</h2>

 </div>

);

/* Products component */

const Products = () => (

 <div>

   <h2>Products</h2>

 </div>

);


/* App component */

const App = () => {

 return (

   <>

     <div>

       <nav className="navbar navbar-light">

         <ul className="nav navbar-nav">

           {/*  Link components are used for linking to other views */}

           <li>

             {" "}

             <Link to="/">Homes</Link>

           </li>

           <li>

             <Link to="/category">Category</Link>

           </li>

           <li>

             <Link to="/products">Products</Link>

           </li>

         </ul>

       </nav>

       {/*  Route components are rendered if the path prop matches the current URL  */}

       <Routes>

         <Route path="/" element={<Home />} />

         <Route path="/category" element={<Category />} />

         <Route path="/products" element={<Products />} />

       </Routes>

     </div>

   </>

 );

};

export default App;

Demo 1: Basic Routing

We’ve declared the components for Home, Category and Products inside App.js. This is fine enough for now, but when the components start to grow bigger, it’s better to have a separate file for each component. As a rule of thumb, we usually create a new file for a component if it occupies more than 10 lines of code. (Starting from the second demo, we’ll be creating a separate file for components that have grown too big to fit inside the App.js file).
Inside the App component, we’ve written the logic for routing. The ‘s path is matched with the current location and a component gets rendered. The component that should be rendered is passed in as the element prop.
Here / matches both / and /category. In previous version of react-router-dom, we have to pass a prop called exact to avoid that both component get rendered.

Router hooks

The react router library embrace the power of hooks, since the fifth version and introduce four differents hooks to help our routing.

  • useNavigate()

  • useLocation()

  • useParams()

  • useRouteMatch()

We are going to explore each one of these hooks in the next slides

useNavigate() and useLocation()

  • useNavigate is a hook that return a function allowing us to change the url whenever we want. It gives the same the result as the Link but it the navigate function can be used inside another function

useParams() and useMatchRoute()

  • useParams(): This hook returns an object that consists of all the parameters in URL.

Protected Routes

Often times when building a web app, you’ll need to protect certain routes in your application from users who don’t have the proper authentication. Protected routes let us choose which routes users can visit based on whether they are logged in. For example, you might have public routes that you want anyone accessing, like a landing page, a pricing page, and the login page. Protected routes should only be available to users that are logged in, like a dashboard or settings page.
Though React Router doesn’t provide any functionality for this out of the box, because it was built with composability in mind, adding it is fairly straightforward.

The PrivateRoute component

Here we define a generic component named PrivateRoute i will check if the user is authentified to access to private route or it will redirect the user to the login page.
The component PrivateRoute will take two props, the first prop is the children ( or we can say which component we are going to protect), the other prop is isAuth which identify if the user is authenticated or not

The PrivateRoute component

Now let’s create the rest our application. In this example we are going to implement them in the same file ( but you have to implement each component in a separate file)

import { Link, Route, Routes } from "react-router-dom";

import PrivateRoute from "./Components/PrivateRoute";
const Home = () => <h1>Home (Public)</h1>;

const Pricing = () => <h1>Pricing (Public)</h1>;

const Dashboard = () => <h1>Dashboard (Private)</h1>;

const Settings = () => <h1>Settings (Private)</h1>;



const Login = () => <h1>TODO</h1>



function Nav() {

 return (

   <nav>



     <Link to="/">Home</Link>

     {` `}

     <Link to="/pricing">Pricing</Link>



   </nav>

 );

}



export default function App() {

 return (

   <div>

     <Nav />



     <Routes>

       <Route path="/" element={<Home />} />

       <Route path="/pricing" element={<Pricing />} />

       <Route path="/dashboard" element={

         <PrivateRoute >

           <Dashboard />

         </PrivateRoute>

       } />

       <Route path="/settings" element={

         <PrivateRoute isAuth={false}>

           < Settings />

         </PrivateRoute>



       } />

       <Route path="/login" element={<Login />} />

     </Routes>

   </div>

 );

}

React Router is a powerful library that complements React by building better and more declarative routes. Unlike the previous versions of React Route, everything is “just components”. Moreover, the new design pattern perfectly fits into the React way of doing things. We've covered:

0
Subscribe to my newsletter

Read articles from Ndungu James K directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Ndungu James K
Ndungu James K

👋 Hi there! I'm Ndung'u James Kinungi, a passionate Full-Stack Software Developer with expertise in modern web technologies. Currently, I’m enrolled in the Full-Stack Development Bootcamp at GomyCode Kenya (May 2024 - December 2024), where I’m refining my skills in building dynamic, user-centric applications from end to end.