DEV Community

Cover image for Routing in React with React Router Dom
Pritpal Singh
Pritpal Singh

Posted on

Routing in React with React Router Dom

Image description

React Router DOM helps you create a Single-Page Application (SPA) where the user can navigate between different components without reloading the page.


Installation

Install React Router DOM using npm:

npm install react-router-dom
Enter fullscreen mode Exit fullscreen mode

BrowserRouter

Wrap your entire app inside BrowserRouter so that the React Router DOM knows how to handle different routes in your app.

import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import App from './App.jsx'
import "./index.css";
import {
  RouterProvider,
  createBrowserRouter,
  createRoutesFromElements,
  Route,
} from "react-router-dom";

createRoot(document.getElementById('root')).render(
  <StrictMode>
    <RouterProvider router={router}/> //router here will be defined in the next step.
  </StrictMode>
)
Enter fullscreen mode Exit fullscreen mode

Here, we are in the main.jsx which is index file for the react application created by using Vite.


Route

Each Route points to a specific component. Route can be nested.

  • path: the URL that users will visit.
  • element: the component that should be displayed when that URL is visited.

There are two ways to define routes here:


//use plain objects
const router = createBrowserRouter([
  {
    path: '/',
    element: <App />,
    children: [
      {
        path: '',
        element: <Home />
      },
      {
        path: 'about',
        element: <About/>
      },
      {
        path: 'contact',
        element: <Contact/>
      },
    ]
  },
])
Enter fullscreen mode Exit fullscreen mode

In this section, we define various routes and the corresponding components that will be displayed for each specific path. For instance, the component <About/> will be rendered when navigating to example.com/about.


Outlet and Nested Routes

When you want to display nested components (like a parent-child structure), you can use Outlet. This allows for nested routes.

In certain web applications, it is necessary to consistently display the same header and footer; to achieve this, we utilize the <Outlet/> tag within App.jsx, establishing it as the primary layout. Alternatively, some developers opt for <layout/> components to fulfill a similar function.

Parent Component:

import { useState } from 'react'
import './App.css'
import { Footer, Header} from './components';
import {Outlet} from "react-router-dom";


export default function App() {

  return (
    <>
      <Header/>
      <Outlet/>
      <Footer/>
    </>
  );
}
Enter fullscreen mode Exit fullscreen mode

Second way to define routes:
This is written in the file - main.jsx and it is also Defining Child Routes

//Configure nested routes with JSX
const router = createBrowserRouter(
  createRoutesFromElements(
    <Route path='/' element={<App />}>
      <Route path='' element={<Home />} />
      <Route path='about' element={<About/>}>
      <Route path='later' element={<Later/>} />
      </Route>
      <Route path='contact' element={<Contact/>} />
      <Route path='user/:id' element={<User/>} />
      <Route path='github' element={<Github/>} />
    </Route>
  )
)
Enter fullscreen mode Exit fullscreen mode

This represents the second and preferred method for defining routes. In this instance, we are nesting routes within the /About path.

When users visit /about/later, the About component will be displayed with Later inside it.


Link Tag

The Link component helps you navigate between pages without refreshing. It’s like an anchor (<a>) tag but works in an SPA.

import React from 'react'
import { Link,} from "react-router-dom";

export default function Footer() {
  return (
    <section>
            <ul>
              <li>
                <Link
                  to={"/about"}
                >
                  About
                </Link>
              </li>
              <li>
                <Link
                  to={"./contact"}
                >
                  Contact Us
                </Link>
              </li>
            </ul>

    </section>
  );
}
Enter fullscreen mode Exit fullscreen mode

NavLink Tag and Active Links

The NavLink component is used to create navigation links that can automatically apply specific styles or classes to the link that matches the current URL (active link).
It uses a className prop, which can be a function to dynamically apply classes.

import React from 'react'
import { NavLink } from "react-router-dom";

export default function Header() {
  return (

        <nav>
          <ul>
            <li>
              <NavLink
                to="/"
                className={({ isActive }) =>
                  `text-sm font-semibold ${
                    isActive ? "text-orange-500" : "text-gray-800"
                  } hover:text-gray-900`
                }
              >
                Home
              </NavLink>
            </li>
            <li>
              <NavLink
                to="/about"
                className={({ isActive }) =>
                  `text-sm font-semibold ${
                    isActive ? "text-orange-500" : "text-gray-800"
                  } hover:text-gray-900`
                }
              >
                About
              </NavLink>
            </li>
            <li>
              <NavLink
                to="/contact"
                className={({ isActive }) =>
                  `text-sm font-semibold ${
                    isActive ? "text-orange-500" : "text-gray-800"
                  } hover:text-gray-900`
                }
              >
                Contact
              </NavLink>
            </li>
          </ul>
        </nav>
  );
}
Enter fullscreen mode Exit fullscreen mode

useParams and Dynamic Segments

In React Router DOM, the useParams hook allows you to access URL parameters from the current route. It is commonly used when you have dynamic routes and need to extract the values from the URL to display specific information or perform certain actions.

First, we need to declare dynamic routes in the main router.

<Route path='user/:id/post/:postid' element={<User/>} />
Enter fullscreen mode Exit fullscreen mode

Then we use useParams hook in the route component.

import React from 'react'
import { useParams } from "react-router-dom";
export default function User() {
    const {id, postid} = useParams();
  return (
    <div>User: {id}, Post: {postid}
    </div>
  )
}
Enter fullscreen mode Exit fullscreen mode

Data Loading

Fetch data from the GitHub API: It retrieves the profile information for the user when the component mounts. The fetched data is stored in the data state variable. The component then displays the number of followers (data.followers) and the user's avatar image (data.avatar_url). If the data fetch fails, the error is logged, and the failed data is stored in the state.

import React,{useState,  useEffect} from 'react'

export default function Github() {
    const [data, setData] = useState([]);

    useEffect(() => {
      fetch("https://api.github.com/users/your_user_name")
        .then((response) => response.json())
        .then((json) => setData(json))
        .catch((data) => {console.log(data)
    setData(data)});
    }, []); 
  return (
    <div>
      <h1>Github Followers: {data.followers} </h1>
      <img src={data.avatar_url} alt="avatar" width="200" />
    </div>
  );
}

Enter fullscreen mode Exit fullscreen mode

Now in React Router DOM v6.4+, you can use loaders to fetch data before rendering a component. Loaders are a part of the new data-fetching capabilities in React Router, allowing you to load data asynchronously before a route renders, rather than fetching it within useEffect inside the component. This improves data loading efficiency and prevents rendering before the data is ready.

  1. In the route configuration, you define a loader function that will fetch the data. This data is then passed to the component through the useLoaderData hook.
<Route loader={githubInfoLoader} path="github" element={<Github />} />
Enter fullscreen mode Exit fullscreen mode
  1. Instead of using useEffect and useState, you use useLoaderData to access the data fetched by the loader.
import React from 'react'
import { useLoaderData } from "react-router-dom";

export default function GithubLoader() {
    const data = useLoaderData();
  return (
    <div>
      <h1>Github Followers: {data.followers} </h1>
      <img src={data.avatar_url} alt="avatar" width="200" />
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

githubinfo.js

export const githubLoaderInfo = async () => {
    const response = await fetch("https://api.github.com/users/username");
    return response.json();
}
Enter fullscreen mode Exit fullscreen mode

We can declare the upper function in the component also but it is not considered a good practice.

Top comments (0)