mcpField
R
react-router

react-router

github.com/claude-dev-suiteDevelopment4637 installsUpdated 3d ago
Repository

About react-router

A reference skill for building React Router applications, aimed at React developers. It covers navigation, route parameters, nested routes, data loading, and common routing pitfalls.

Key features

  1. 01Links and programmatic navigation
  2. 02Route and query parameters
  3. 03Nested and protected routes
  4. 04Loaders and error boundaries
  5. 05Routing practices and troubleshooting

Use cases

  1. 01Configure navigation in a React app
  2. 02Build nested pages with shared layouts
  3. 03Load data through route loaders
  4. 04Handle protected routes and routing errors

MCP support

The skill references `mcp__documentation__fetch_docs` for React Router documentation.

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/claude-dev-suite/claude-dev-suite --skill react-router

After installing, type/react-routerin Claude Code to confirm it loaded.

Bundled filesadvanced.md

Details

From the project README

React Router

Deep Knowledge: Use mcp__documentation__fetch_docs with technology: react topic: router for comprehensive documentation on React Router v6+ patterns and data loading.

Full Reference: See advanced.md for Data Loading (v6.4+), Actions, Code Splitting, Route Configuration, Error Handling, Scroll Restoration, Modal Routes, and TypeScript Integration.

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" element={<Users />} />
        <Route path="*" element={<NotFound />} />
      </Routes>
    </BrowserRouter>
  );
}

Navigation

Link Component
import { Link, NavLink } from 'react-router-dom';

function Navigation() {
  return (
    <nav>
      {/* Basic link */}
      <Link to="/">Home</Link>

      {/* NavLink with active styling */}
      <NavLink
        to="/about"
        className={({ isActive, isPending }) =>
          isActive ? 'active' : isPending ? 'pending' : ''
        }
      >
        About
      </NavLink>

      {/* With state */}
      <Link to="/dashboard" state={{ from: 'home' }}>
        Dashboard
      </Link>

      {/* Replace instead of push */}
      <Link to="/login" replace>
        Login
      </Link>
    </nav>
  );
}
Programmatic Navigation
import { useNavigate, useLocation } from 'react-router-dom';

function LoginButton() {
  const navigate = useNavigate();
  const location = useLocation();

  const handleLogin = async () => {
    await login();

    // Navigate with state
    navigate('/dashboard', {
      state: { from: location },
      replace: true,
    });
  };

  const handleBack = () => {
    navigate(-1); // Go back
  };

  return (
    <div>
      <button onClick={handleLogin}>Login</button>
      <button onClick={handleBack}>Back</button>
    </div>
  );
}

Route Parameters

Dynamic Segments
<Routes>
  <Route path="/users/:userId" element={<UserProfile />} />
  <Route path="/posts/:postId/comments/:commentId" element={<Comment />} />
</Routes>

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

function UserProfile() {
  const { userId } = useParams<{ userId: string }>();

  return <div>User ID: {userId}</div>;
}

function Comment() {
  const { postId, commentId } = useParams();

  return (
    <div>
      Post: {postId}, Comment: {commentId}
    </div>
  );
}
Optional Segments
<Routes>
  {/* Optional lang parameter */}
  <Route path="/:lang?/products" element={<Products />} />

  {/* Catch-all (splat) */}
  <Route path="/files/*" element={<FileExplorer />} />
</Routes>

function FileExplorer() {
  const { '*': filePath } = useParams();
  // /files/documents/report.pdf → filePath = "documents/report.pdf"

  return <div>Path: {filePath}</div>;
}

Query Parameters

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

function ProductList() {
  const [searchParams, setSearchParams] = useSearchParams();

  const category = searchParams.get('category') || 'all';
  const page = parseInt(searchParams.get('page') || '1');
  const sort = searchParams.get('sort') || 'name';

  const updateFilters = (newCategory: string) => {
    setSearchParams({
      category: newCategory,
      page: '1', // Reset page
      sort,
    });
  };

  const nextPage = () => {
    setSearchParams(prev => {
      prev.set('page', String(page + 1));
      return prev;
    });
  };

  return (
    <div>
      <select
        value={category}
        onChange={(e) => updateFilters(e.target.value)}
      >
        <option value="all">All</option>
        <option value="electronics">Electronics</option>
      </select>

      <ProductGrid category={category} page={page} sort={sort} />

      <button onClick={nextPage}>Next Page</button>
    </div>
  );
}

Nested Routes

// Route configuration
<Routes>
  <Route path="/dashboard" element={<DashboardLayout />}>
    <Route index element={<DashboardHome />} />
    <Route path="analytics" element={<Analytics />} />
    <Route path="settings" element={<Settings />} />
    <Route path="users">
      <Route index element={<UserList />} />
      <Route path=":userId" element={<UserDetail />} />
      <Route path="new" element={<NewUser />} />
    </Route>
  </Route>
</Routes>

// Parent layout with Outlet
import { Outlet, Link } from 'react-router-dom';

function DashboardLayout() {
  return (
    <div className="dashboard">
      <nav className="sidebar">
        <Link to="/dashboard">Home</Link>
        <Link to="/dashboard/analytics">Analytics</Link>
        <Link to="/dashboard/settings">Settings</Link>
        <Link to="/dashboard/users">Users</Link>
      </nav>

      <main className="content">
        {/* Child routes render here */}
        <Outlet />
      </main>
    </div>
  );
}
Relative Links
function UserDetail() {
  const { userId } = useParams();

  return (
    <div>
      <h1>User {userId}</h1>

      {/* Relative to current route */}
      <Link to="edit">Edit User</Link>      {/* → /dashboard/users/:userId/edit */}
      <Link to="../">Back to List</Link>    {/* → /dashboard/users */}
      <Link to="../../">Dashboard</Link>    {/* → /dashboard */}
    </div>
  );
}

Protected Routes

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

function ProtectedRoute({ children }: { children?: ReactNode }) {
  const { user, isLoading } = useAuth();
  const location = useLocation();

  if (isLoading) {
    return <LoadingSpinner />;
  }

  if (!user) {
    // Redirect to login, preserving intended destination
    return <Navigate to="/login" state={{ from: location }} replace />;
  }

  return children ?? <Outlet />;
}

// Usage
<Routes>
  <Route path="/login" element={<Login />} />

  {/* Protected routes */}
  <Route element={<ProtectedRoute />}>
    <Route path="/dashboard" element={<Dashboard />} />
    <Route path="/settings" element={<Settings />} />
    <Route path="/profile" element={<Profile />} />
  </Route>
</Routes>

// Role-based protection
function AdminRoute({ children }: { children?: ReactNode }) {
  const { user } = useAuth();

  if (user?.role !== 'admin') {
    return <Navigate to="/unauthorized" replace />;
  }

  return children ?? <Outlet />;
}

<Routes>
  <Route element={<ProtectedRoute />}>
    <Route path="/dashboard" element={<Dashboard />} />

    {/* Admin only */}
    <Route element={<AdminRoute />}>
      <Route path="/admin" element={<AdminPanel />} />
      <Route path="/users/manage" element={<UserManagement />} />
    </Route>
  </Route>
</Routes>

Best Practices

  • Use nested routes for shared layouts
  • Use loaders for data fetching (v6.4+)
  • Implement proper error boundaries
  • Use relative links in nested routes
  • Lazy load route components
  • Preload on user intent (hover)
  • Don't fetch data in useEffect when loaders available
  • Don't hardcode paths - use relative navigation
  • Don't forget to handle loading states

When NOT to Use This Skill

  • Next.js applications - Use Next.js App Router or Pages Router instead
  • Server-side routing - Use framework-specific routing (Express, etc.)
  • Simple conditional rendering - Use react skill for basic show/hide logic
  • Static sites - Consider if routing library is needed

Anti-Patterns

Anti-PatternProblemSolution
Fetching in useEffect with loaders availableWaterfall loading, slower UXUse loader functions
Hardcoding absolute pathsHard to refactor, breaks nested routesUse relative paths
Not handling loading statesPoor UXUse useNavigation or Suspense
Missing error boundariesApp crashes on route errorsAdd errorElement to routes
Not lazy loading routesLarge initial bundleUse React.lazy() for routes
Using index as route keyIncorrect behaviorDon't use keys for routes
Forgetting to handle 404Blank page or crashAdd catch-all route with path="*"

Quick Troubleshooting

IssueLikely CauseFix
Route not matchingWrong path syntaxCheck path definition, use exact paths
Link not workingWrong to propVerify path starts with / or is relative
Params undefinedUsing wrong hookUse useParams() for route params
Navigation not workingWrong hookUse useNavigate() for programmatic navigation
Nested route not showingMissing OutletAdd in parent component
Loader not calledUsing Routes instead of RouterProviderUse createBrowserRouter with loaders
Protected route not workingWrong redirect logicCheck authentication state and Navigate component

Reference Documentation

Comments

Markdown supported