Agent Skills: React Router Skill

Master React Router v6 for production routing with error boundaries, lazy loading, and navigation guards

UncategorizedID: pluginagentmarketplace/custom-plugin-react/react-router

Skill Files

Browse the full folder contents for react-router.

Download Skill

Loading file tree…

skills/react-router/SKILL.md

Skill Metadata

Name
react-router
Description
Master React Router v6 for production routing with error boundaries, lazy loading, and navigation guards

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

  1. Build multi-page app with navigation
  2. Implement nested dashboard routes
  3. Create protected authentication routes
  4. Build dynamic product detail pages
  5. Implement search with URL params
  6. Create breadcrumb navigation
  7. 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