React

Chapter 12: React Router v6+ — Client-side routing, dynamic URL parameters, nested routes with Outlet, NavLink active states, and protected route guards.

1. Client-Side Routing (SPA Navigation)

In traditional multi-page websites, clicking a link causes the browser to request a brand-new HTML document from the server, causing a blank white screen flash. In a React Single Page Application (SPA), React Router intercepts URL changes and renders the corresponding component tree instantaneously without refreshing the browser.

💡 Real-World Analogy: Stage Curtain Backdrop Switcher

Think of visiting different pages on a website:

  • Server-Side Routing (Old Web): Tearing down the entire theater building and constructing a new theater down the street just to change from Act 1 to Act 2!
  • Client-Side Routing (React Router): The theater (SPA container) stays put. The stagehands simply swap the painted background curtain (<Dashboard /> $\rightarrow$ <Profile />) smoothly in milliseconds!

2. Core React Router v6+ Setup

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

function App() {
    return (
        <BrowserRouter>
            {/* 1. Global Navigation Bar */}
            <nav className="navbar">
                <NavLink to="/" className={({ isActive }) => isActive ? "nav-link active" : "nav-link"}>
                    Home
                </NavLink>
                <NavLink to="/courses" className={({ isActive }) => isActive ? "nav-link active" : "nav-link"}>
                    Courses
                </NavLink>
                <NavLink to="/about" className={({ isActive }) => isActive ? "nav-link active" : "nav-link"}>
                    About
                </NavLink>
            </nav>

            {/* 2. Route Switcher */}
            <Routes>
                <Route path="/" element={<HomePage />} />
                <Route path="/courses" element={<CoursesPage />} />
                <Route path="/courses/:courseId" element={<CourseDetail />} />
                <Route path="*" element={<NotFound404 />} />
            </Routes>
        </BrowserRouter>
    );
}
Client-Side Router Navigation Output:
Home (Active) Courses About ⚡ Instant 0ms render

3. Dynamic Route Parameters & Nested Layouts

1. useParams Hook: Reading URL Segments (/courses/:id)

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

function CourseDetail() {
    // Reads :courseId from the URL path:
    const { courseId } = useParams();

    return (
        <div className="course-detail-view">
            <h2>Viewing Course #{courseId}</h2>
            <p>Loaded curriculum content for track: {courseId}</p>
        </div>
    );
}

2. Nested Routes & Shared Layouts with <Outlet />

// Layout component with persistent Sidebar & dynamic Outlet slot:
import { Outlet } from "react-router-dom";

function DashboardLayout() {
    return (
        <div className="dashboard-grid">
            <aside className="sidebar">
                <Link to="/dashboard/analytics">Analytics</Link>
                <Link to="/dashboard/settings">Settings</Link>
            </aside>
            <main className="dashboard-content">
                {/* Child route components render inside <Outlet /> */}
                <Outlet />
            </main>
        </div>
    );
}

// Router Configuration:
<Route path="/dashboard" element={<DashboardLayout />}>
    <Route path="analytics" element={<AnalyticsView />} />
    <Route path="settings" element={<SettingsView />} />
</Route>
Nested Layout <Outlet /> Preview:
Sidebar
• Analytics
• Settings
<Outlet /> Active Slot

Analytics Overview Component

4. Hands-On Practice Challenges

Master dynamic route matching, query string parsing, and protected authentication guards. Click "Solve Challenge" to open the code editor!

🎯 Hands-on Coding Challenge Route Matching Engine

Challenge 1: Replicate useParams Route Matcher

Write an algorithm matchRoutePath(routePattern, currentUrl) that extracts dynamic URL parameters (e.g., /courses/:trackId/:lessonNum matched against /courses/react/28 yields { trackId: 'react', lessonNum: '28' }).

📋 Requirements & What to Write:
  • Split paths by / and match segment counts.
  • Extract segments prefixed with : into the params object.
  • Return { isMatch: true, params } on match or null on mismatch.
Expected Result: { isMatch: true, params: { trackId: "react", lessonNum: "28" } }
💡
Editor Instructions: Complete matchRoutePath to parse dynamic URL segments.
routeMatcher.js
Console / Terminal Output
// Output will appear here when you click "Run Code"...
🎯 Hands-on Coding Challenge Query String Parser

Challenge 2: useSearchParams Query String Parser

Implement a URL query string parser parseQueryParameters(queryString) that converts query strings like ?q=react&sort=desc into a key-value object.

📋 Requirements & What to Write:
  • Strip leading ? if present.
  • Split pairs on & and key/value on =.
  • Use decodeURIComponent for clean string decoding.
Expected Result: { q: "react+router", filter: "active", sort: "desc" }
💡
Editor Instructions: Complete parseQueryParameters to decode URL query strings.
queryParser.js
Console / Terminal Output
// Output will appear here when you click "Run Code"...
🎯 Hands-on Coding Challenge Protected Route Guard

Challenge 3: Protected Route Auth Guard Simulator

Implement a route guard guardRouteAccess(userAuth, targetPath) that redirects unauthenticated users attempting to access protected routes (/dashboard, /admin) to /login.

📋 Requirements & What to Write:
  • If protected and not logged in, redirect to /login?redirect=<path>.
  • If admin route and role is not admin, redirect to /unauthorized.
  • Otherwise return { allow: true, render: targetPath }.
Expected Result: Guest: { allow: false, redirect: "/login?redirect=%2Fdashboard%2Fanalytics" } | Admin: { allow: true, render: "/admin/settings" }
💡
Editor Instructions: Enforce routing permissions based on user authentication status.
routeGuard.js
Console / Terminal Output
// Output will appear here when you click "Run Code"...