react-router

v2026.09.24

React Router v6+ for client-side routing. Covers BrowserRouter, Routes, navigation, data loading, nested routes, protected routes, and code splitting. USE WHEN: user mentions "React Router", "routing", "navigation", "BrowserRouter", "Routes", "useNavigate", "Link", "nested routes", asks about "client-side routing", "protected routes", "route parameters", "loaders" DO NOT USE FOR: Next.js routing - use Next.js skill instead, Server-side routing - use framework-specific skills, basic React navigation - use `react` skill for simple conditional rendering

GitHub
安装命令
npx skhub add claude-dev-suite/react-router
Markdown
SKILL.md

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 <Outlet /> 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

发现
标签

此技能尚未发布标签。

版本
最新版本元数据

版本

v2026.09.24

发布时间

Sep 24, 2026

分类

未分类

许可证

MIT

源路径

skills/frontend-frameworks/react-router

默认分支

main

最新提交

9496306

Tree SHA

fe4e2f1