DEV Community

Cover image for React Router Basics to Advanced (v6+)
Rishabh Joshi
Rishabh Joshi

Posted on

1

React Router Basics to Advanced (v6+)

What is ROUTING?

Routing refers to the process of navigating between different pages or views in a single-page application (SPA) without reloading the entire page.

  • It keeps the UI in sync with the current browser URL.
  • Allows us to build Single Page Applications (SPA).

Why Routing in React?

React apps are SPAs, meaning there's only one HTML file (index.html), but multiple views (pages) that users can navigate to. Routing helps manage these views by matching the URL to the correct component.

It enables client-side navigation without full-page reloads, allowing users to move smoothly between URLs like /home, /about, or /contact, each displaying different components.

React doesn’t have built-in routing, so we use a library like React Router (react-router-dom) for handling routing.


What is a Single Page Application (SPA)?

A Single Page Application (SPA) dynamically updates the page without reloading it, providing a seamless user experience.

  • Runs entirely in the browser (Client Side).
  • Different URLs load different React components.
  • Uses JavaScript (React) to update the UI dynamically.
  • Fetches additional data via APIs (e.g., from a backend server).

When the user clicks a link, the URL updates, and React dynamically loads the corresponding component.


React Router

React Router is the most popular library to handle navigation inside a React app.

  • Enables URL-based navigation.
  • Changes browser URLs without refreshing the page.
  • Keeps the UI in sync with the URL.

🔧 Installation

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

Defining Routes

With routing, we match different URLs to different UI views. In the case of React, we match a URL to a specific React Component, and we call each of these matches routes.

Since React Router v6.4, there are two main ways to define routes. We'll focus on the traditional declarative way.

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

function App() {
  return (
    <BrowserRouter>       {/* 🚀 Enables routing */}
      <Routes>            {/* 🚦 Manages route paths */}
        <Route index element={<Home />} />  {/* Default route */}
        <Route path="/about" element={<About />} />
      </Routes>
    </BrowserRouter>
  );
}

function Nav() {
  return (
    <nav>
      <Link to="/">Home</Link>         {/* Link to Home */}
      <Link to="/about">About</Link>   {/* Link to About */}
    </nav>
  );
}
Enter fullscreen mode Exit fullscreen mode

Key Concepts 🔑

  1. <BrowserRouter> – The Router Provider

    • It's the top-level component that enables routing in your React application.
    • It leverages the HTML5 History API to keep your UI synchronized with the browser URL.
    • Crucially, without <BrowserRouter>, React Router won't be able to manage your application's routes.
  2. <Routes> – Routing Container

    • This component acts as a container for your individual <Route> definitions.
    • It intelligently iterates through its <Route> children and renders the first one whose path matches the current browser URL.
    • Think of <Routes> as a central highway dispatcher, directing traffic to the appropriate exits.
    • It's the successor to the older <Switch> component in previous versions of React Router.
  3. <Route> – Define a Path and Component

    • Each <Route> component serves as a mapping between a specific URL path and a corresponding React component.
    • When the browser URL matches the path of a <Route>, that route's element (the React component) is rendered.
    • index prop defines the default child route (instead of path="/").
    • Page Not Found Handling:
      <Route index element={<Home />} />
      <Route path="*" element={<PageNotFound />} />
    

    The path="*" acts as a catch-all. If no other defined route matches the current URL, this route will be matched, and the <PageNotFound> component will be displayed.

  4. <NavLink> / <Link> – Navigation Without Reload

    • These components are your primary tools for navigating between different routes within your SPA without triggering a full page reload from the server.
    • They render as standard <a> tags in the HTML but intercept the click event to perform client-side navigation managed by React Router.
    • <NavLink> vs. <Link>:
      • <NavLink> is a specialized version of <Link> that provides built-in styling capabilities for the currently active route.
      • It automatically applies an active class (by default) to the rendered link when its to prop matches the current URL.
      • You can customize this behavior using the className or style props, or by using the isActive prop for more fine-grained control.
    import { NavLink } from "react-router-dom";
    
    function Navigation() {
      return (
        <nav>
          <NavLink to="/">Home</NavLink>
          <NavLink to="/about">About</NavLink>
        </nav>
      );
    }
    
  5. Nested Routes

    • As your application grows, you might encounter scenarios where certain sections have their own sub-navigation and views. This is where nested routes come in handy.
    • Imagine a /dashboard section with sub-pages like /dashboard/profile and /dashboard/settings.
    • To implement this, you define child <Route> components within a parent <Route>.
    • The key to rendering the content of these nested routes is the <Outlet /> component in the parent route's component.
    <Routes>
        <Route path="/dashboard" element={<Dashboard />}>
            <Route path="profile" element={<Profile />} />
            <Route path="settings" element={<Settings />} />
        </Route>
    </Routes>
    
  6. <Outlet> in React Router

    • The <Outlet> component serves as a placeholder in the component rendered by a parent route.
    • When a child route of that parent route matches the current URL, its corresponding component is rendered inside the <Outlet> within the parent.
    • Why is <Outlet> essential?
      • It enables you to create reusable layouts. Common UI elements like navigation bars, sidebars, and footers can be defined in the parent component, while the specific content for the child routes is dynamically injected into the <Outlet>.
      • This promotes a clean and organized component structure.
    import { Outlet, Link } from "react-router-dom";
    
    const Dashboard = () => {
      return (
        <div>
          <nav>
            <Link to="/profile">Profile</Link>
            <Link to="/settings">Settings</Link>
          </nav>
    
          <hr />
          <Outlet />     {/* Child route components will be rendered here */}
        </div>
      );
    };
    
    export default Dashboard;
    

Dynamic Routes with URL Parameters

Dynamic routes allow you to create routes that can handle variable parts of the URL. This is useful for displaying details of a specific item, like a product or a user profile.

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

function ProductDetails() {
  const { productId } = useParams();
  return <div>Product ID: {productId}</div>;
}

function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/products/:productId" element={<ProductDetails />} />
      </Routes>
    </BrowserRouter>
  );
}
Enter fullscreen mode Exit fullscreen mode
  • useParams() hook: This React Router hook allows you to access the dynamic parameters from the current URL. You can call this hook within the functional component rendered by the dynamic route (in this case, ProductDetails). It returns an object where the keys are the parameter names defined in the path (e.g., productId) and the values are the corresponding segments from the URL.
  • /:productId: This syntax within the path prop of the <Route> defines a dynamic segment. Any value in this position of the URL will be captured as the productId parameter. For example, if the URL is /products/42, the useParams() hook in ProductDetails will return { productId: "42" }.

Programmatic Navigation

useNavigate Hook

The useNavigate hook allows you to programmatically navigate to different routes. This is often used after actions like form submissions or for handling authentication redirects.

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

function Home() {
  const navigate = useNavigate();
  const handleClick = () => {
    navigate('/about');
  };
  return <button onClick={handleClick}>Go to About</button>;
}
Enter fullscreen mode Exit fullscreen mode

<Navigate /> Component

The <Navigate /> component is used to redirect the user to a different route, often based on certain conditions like user authentication

import { Navigate } from 'react-router-dom';

function ProtectedRoute({ isLoggedIn, children }) {
  if (!isLoggedIn) {
    return <Navigate to="/login" replace />;
  }
  return children;
}
Enter fullscreen mode Exit fullscreen mode
  • replace prop: Replaces the current entry in the history stack.
  • This is useful for auth checks and redirection.

How Routing Changes Component Structure in React

  • Without Router (Traditional Component Structure) Normally, in a simple React app (without a router), we structure components inside the App component like this:
function App() {
  return (
    <div>
      <Header />
      <Main />
      <Footer />
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Here, App acts like a parent container that holds all components, and all of them are typically rendered together.

  • When React Router Comes Into Play When we introduce React Router, the way we structure App changes. Instead of keeping all components directly inside App, we primarily keep the <BrowserRouter>, <Routes>, and <Route> configurations there. The actual page content is rendered by the components matched by the routes.

Why?

  1. Routing Controls What to Show

    • Before Router: App always renders everything.
    • With Router: Different pages (routes) should load only when needed.
  2. Why is this better? 📌

    • Improved Performance: Only the required components for the current route are loaded and rendered, reducing the initial load time and improving overall performance.
    • Smoother User Experience: Navigation between different views happens without full page reloads, providing a more seamless and faster user experience.

Understanding React Router with a Highway Analogy

React Router Concept Real-World Analogy
BrowserRouter 🛣️ The road network that enables travel. Without it, there are no roads.
Routes 🚗 The highway with multiple exits (routes).
Route 🛑 A specific exit that leads to a destination (component).
Link 🚦 Signboards that direct users to different routes.
<Outlet /> 🛣️ The location on the highway where nested exits merge.
  • Without BrowserRouter, there are no roads!
  • Without Routes, there are no exits!
  • Without Route, you can’t reach your destination!
  • Without Outlet, nested routes have nowhere to render.

✨ Final Thoughts

Routing is the backbone of navigation in modern React applications. It allows us to create multi-page experiences without full page reloads, making our apps feel faster, more dynamic, and more like native applications.

With React Router, we can:

  • Map URLs to components easily.
  • Enable smooth client-side navigation.
  • Organize large applications into clean, scalable route structures.
  • Enhance user experience with dynamic routing, nested layouts, protected routes, and programmatic navigation.

As you build more advanced React apps, mastering routing will unlock a whole new level of power and flexibility in your projects.

In short, React Router bridges the gap between a simple app and a fully functional web experience. 🚀


📚 What's Next?

This post focused on the traditional declarative routing using React Router 6.
However, to keep things clean and digestible, I’ll cover some advanced topics separately in the next post:

  • Using Suspense with React Router (for lazy loading routes) ⚡
  • New Features and Changes in React Router v7🆕

Stay tuned for a deep dive into modern routing patterns and performance optimization techniques coming soon!

Heroku

Deploy with ease. Manage efficiently. Scale faster.

Leave the infrastructure headaches to us, while you focus on pushing boundaries, realizing your vision, and making a lasting impression on your users.

Get Started

Top comments (2)

Collapse
 
nevodavid profile image
Nevo David

insane how clean you can make the app structure with just a few lines. ever notice if super fancy routing setups actually help or just make things messy over time?

SurveyJS custom survey software

JavaScript Form Builder UI Component

Generate dynamic JSON-driven forms directly in your JavaScript app (Angular, React, Vue.js, jQuery) with a fully customizable drag-and-drop form builder. Easily integrate with any backend system and retain full ownership over your data, with no user or form submission limits.

Learn more