14. React Router v6+

Chapter 14: Routing with React Router v6+

In Single Page Applications (SPAs), users expect the fluidity of a desktop app combined with standard web capabilities: shareable URLs, browser back/forward button navigation, and deep-linking. Learn how React Router v6+ facilitates client-side routing, nested layouts, and protected routes.

1. How Client-Side Routing Works (HTML5 History API)

In traditional multi-page web applications, clicking an anchor tag (<a href="/about">) instructs the browser to tear down the entire page, make an HTTP request to the server, and download a brand-new HTML document.

In contrast, React Router leverages the browser's native HTML5 History API (window.history.pushState). When a user clicks a link:

  • The URL in the address bar updates immediately without a network round-trip.
  • React Router listens to the location change event (popstate).
  • React unmounts the old view component and mounts the new view component into the DOM in milliseconds.

2. Installation & Core Components

Install the official router package for web applications:

npm install react-router-dom

Basic Router Configuration:

import { BrowserRouter, Routes, Route, Link, NavLink } from 'react-router-dom';

function App() {
  return (
    <BrowserRouter>
      {/* Global Navigation Header */}
      <nav className="navbar">
        <NavLink to="/" className={({ isActive }) => isActive ? "nav-active" : "nav-link"}>
          Home
        </NavLink>
        <NavLink to="/catalog" className={({ isActive }) => isActive ? "nav-active" : "nav-link"}>
          Catalog
        </NavLink>
      </nav>

      {/* Route Switchboard */}
      <main className="page-content">
        <Routes>
          <Route path="/" element={<HomePage />} />
          <Route path="/catalog" element={<CatalogPage />} />
          <Route path="/catalog/:productId" element={<ProductDetailsPage />} />
          {/* Wildcard 404 Catch-All */}
          <Route path="*" element={<NotFoundPage />} />
        </Routes>
      </main>
    </BrowserRouter>
  );
}

3. Dynamic Route Parameters & Query Strings

`useParams` (Dynamic URL Segments)

Extracts variables declared with a colon in the route path (e.g., /catalog/:productId):

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

function ProductDetailsPage() {
  // If URL is /catalog/shoes-99:
  const { productId } = useParams();

  return <h2>Viewing Product: {productId}</h2>;
}

`useSearchParams` (Query Strings)

Reads and updates query parameters (e.g., /search?q=react&page=2):

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

function SearchPage() {
  const [searchParams, setSearchParams] = useSearchParams();
  const query = searchParams.get('q') || '';

  return (
    <input 
      value={query} 
      onChange={(e) => setSearchParams({ q: e.target.value })} 
      placeholder="Filter products..." 
    />
  );
}

4. Nested Routes & The `<Outlet />` Component

In large dashboards, navigation sidebars and top headers should remain persistent while only the main inner panel changes. React Router v6 implements this through nested routes and the <Outlet /> component:

// 1. Dashboard Layout Shell
import { Outlet, NavLink } from 'react-router-dom';

function DashboardLayout() {
  return (
    <div className="dashboard-grid">
      <aside className="sidebar">
        <NavLink to="/dashboard/analytics">Analytics</NavLink>
        <NavLink to="/dashboard/settings">Settings</NavLink>
      </aside>

      <section className="main-panel">
        {/* The matching child route is rendered right here! */}
        <Outlet />
      </section>
    </div>
  );
}

// 2. Defining Nested Route Hierarchy:
<Route path="/dashboard" element={<DashboardLayout />}>
  <Route path="analytics" element={<AnalyticsView />} />
  <Route path="settings" element={<SettingsView />} />
</Route>

5. Protected Routes & Authentication Guards

To protect restricted screens (like user profiles or payment portals), create an authentication guard wrapper:

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

function ProtectedRoute({ isAuthenticated }) {
  if (!isAuthenticated) {
    // Redirect unauthenticated user to login screen
    return <Navigate to="/login" replace />;
  }

  // Render child routes if authenticated
  return <Outlet />;
}

// In App Router:
<Routes>
  <Route path="/login" element={<LoginPage />} />

  {/* Guarded Routes */}
  <Route element={<ProtectedRoute isAuthenticated={userToken !== null} />}>
    <Route path="/account" element={<AccountPage />} />
    <Route path="/orders" element={<OrdersPage />} />
  </Route>
</Routes>

Frequently Asked Questions (FAQ)

How does client-side routing in React differ from traditional server routing?

In traditional server routing, clicking a link sends a fresh HTTP request to the web server, which sends back an entirely new HTML document, causing a full-page reload and flashing screen. In client-side routing (React Router), the browser's HTML5 History API (pushState) updates the URL path while React intercepts the navigation, swapping out only the necessary view components in memory instantly without a full page refresh.

What is the purpose of the <Outlet /> component in React Router v6?

<Outlet /> is a placeholder component used inside parent layout routes. When a child route matches the current URL, React Router renders that child route's component inside the parent's <Outlet /> slot, enabling persistent shared layouts (like sidebars and navigation headers).

What is the difference between <Link> and <NavLink>?

<Link> creates an accessible HTML anchor tag that prevents browser page reloads and navigates to the target URL. <NavLink> is a specialized version of <Link> that automatically applies an 'active' CSS class or provides an isActive boolean prop when its href matches the current browser location, ideal for navigation menus.

How do you implement a 404 Not Found page in React Router v6?

Add a Route at the very end of your <Routes> definition with the wildcard path path='*' (e.g., <Route path='*' element={<NotFoundPage />} />). React Router will render this component whenever no other declared route matches the current URL.

Explore Related Tools

Hand-picked utilities and calculators related to this tool.

Related Tools