| name | react-router |
| description | Master React Router v6 for production routing with error boundaries, lazy loading, and navigation guards |
| sasmp_version | 2.0.0 |
| bonded_agent | 05-routing-navigation |
| bond_type | PRIMARY_BOND |
| input_validation | [object Object] |
| output_format | [object Object] |
| error_handling | [object Object] |
| observability | [object Object] |
React Router Skill
Overview
Master React Router v6 for building single-page applications with client-side routing, including nested routes, protected routes, and navigation patterns.
Learning Objectives
- Configure React Router
- Implement nested and dynamic routes
- Use navigation hooks and components
- Build protected routes
- Handle route parameters and search params
Quick Start
Installation
npm install react-router-dom
Basic Setup
import { BrowserRouter, Routes, Route } from 'react-router-dom';
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/users/:userId" element={<UserProfile />} />
<Route path="*" element={<NotFound />} />
</Routes>
</BrowserRouter>
);
}
Navigation
Link Component
import { Link, NavLink } from 'react-router-dom';
function Nav() {
return (
<nav>
<Link to="/">Home</Link>
<NavLink to="/about" className={({ isActive }) => isActive ? 'active' : ''}>
About
</NavLink>
</nav>
);
}
Programmatic Navigation
import { useNavigate } from 'react-router-dom';
function LoginForm() {
const navigate = useNavigate();
const handleSubmit = async (credentials) => {
await login(credentials);
navigate('/dashboard'); // Navigate after login
// navigate(-1); // Go back
// navigate('/home', { replace: true }); // Replace history
};
return <form onSubmit={handleSubmit}>...</form>;
}
Route Parameters
import { useParams } from 'react-router-dom';
// Route: /users/:userId
function UserProfile() {
const { userId } = useParams();
return <div>User ID: {userId}</div>;
}
// Multiple params: /posts/:postId/comments/:commentId
function Comment() {
const { postId, commentId } = useParams();
// ...
}
Search Parameters
import { useSearchParams } from 'react-router-dom';
function ProductList() {
const [searchParams, setSearchParams] = useSearchParams();
const category = searchParams.get('category') || 'all';
const sort = searchParams.get('sort') || 'name';
const updateCategory = (newCategory) => {
setSearchParams({ category: newCategory, sort });
};
return (
<div>
{/* URL: /products?category=electronics&sort=price */}
<select value={category} onChange={(e) => updateCategory(e.target.value)}>
<option value="all">All</option>
<option value="electronics">Electronics</option>
</select>
</div>
);
}
Nested Routes
import { Outlet } from 'react-router-dom';
function DashboardLayout() {
return (
<div>
<DashboardNav />
<main>
<Outlet /> {/* Child routes render here */}
</main>
</div>
);
}
// Route configuration
<Route path="/dashboard" element={<DashboardLayout />}>
<Route index element={<DashboardHome />} />
<Route path="profile" element={<Profile />} />
<Route path="settings" element={<Settings />} />
</Route>
Protected Routes
import { Navigate, useLocation } from 'react-router-dom';
function ProtectedRoute({ children }) {
const { user } = useAuth();
const location = useLocation();
if (!user) {
return <Navigate to="/login" state={{ from: location }} replace />;
}
return children;
}
// Usage
<Route
path="/dashboard"
element={
<ProtectedRoute>
<Dashboard />
</ProtectedRoute>
}
/>
Code Splitting
import { lazy, Suspense } from 'react';
const Home = lazy(() => import('./pages/Home'));
const Dashboard = lazy(() => import('./pages/Dashboard'));
function App() {
return (
<Suspense fallback={<Spinner />}>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/dashboard" element={<Dashboard />} />
</Routes>
</Suspense>
);
}
Practice Exercises
- Build multi-page app with navigation
- Implement nested dashboard routes
- Create protected authentication routes
- Build dynamic product detail pages
- Implement search with URL params
- Create breadcrumb navigation
- Build modal routes
Resources
Error Boundary Pattern
import { useRouteError, isRouteErrorResponse } from 'react-router-dom';
function RouteErrorBoundary() {
const error = useRouteError();
if (isRouteErrorResponse(error)) {
if (error.status === 404) {
return <NotFoundPage />;
}
return <ErrorPage status={error.status} message={error.statusText} />;
}
return <ErrorPage message="Something went wrong" />;
}
// Router configuration with error handling
const router = createBrowserRouter([
{
path: '/',
element: <RootLayout />,
errorElement: <RouteErrorBoundary />,
children: [/* routes */],
},
]);
Lazy Loading with Retry
function lazyWithRetry(importFn, retries = 3) {
return lazy(async () => {
for (let i = 0; i < retries; i++) {
try {
return await importFn();
} catch (err) {
if (i === retries - 1) throw err;
await new Promise(r => setTimeout(r, 1000 * Math.pow(2, i)));
}
}
});
}
const Dashboard = lazyWithRetry(() => import('./Dashboard'));
Unit Test Template
import { render, screen } from '@testing-library/react';
import { MemoryRouter, Routes, Route } from 'react-router-dom';
describe('Routing', () => {
it('renders correct route', () => {
render(
<MemoryRouter initialEntries={['/dashboard']}>
<Routes>
<Route path="/dashboard" element={<Dashboard />} />
</Routes>
</MemoryRouter>
);
expect(screen.getByText(/dashboard/i)).toBeInTheDocument();
});
});
Version: 2.0.0 Last Updated: 2025-12-30 SASMP Version: 2.0.0 Difficulty: Intermediate Estimated Time: 1-2 weeks Prerequisites: React Fundamentals Changelog: Added error boundaries, lazy retry, and test templates