mcpField
R
react-router

react-router

github.com/claude-dev-suite開発4637 回インストール3 日前に更新
リポジトリ

react-router について

React 開発者向けの React Router 構築リファレンススキルです。ナビゲーション、ルートパラメーター、ネストしたルート、データ読み込み、よくある問題を扱います。

主な機能

  1. 01リンクとプログラムによるナビゲーション
  2. 02ルートパラメーターとクエリパラメーター
  3. 03ネストしたルートと保護ルート
  4. 04ローダーとエラーバウンダリー
  5. 05ルーティングの実践とトラブルシューティング

活用シーン

  1. 01React アプリのナビゲーション設定
  2. 02共有レイアウトを使ったネストページの構築
  3. 03ルートローダーによるデータ読み込み
  4. 04保護ルートやルーティングエラーへの対応

MCP 対応

React Router のドキュメント取得手段として `mcp__documentation__fetch_docs` に言及しています。

インストール

コマンドをコピーしてターミナルで実行します。

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

インストール後、Claude Code で/react-routerを入力して読み込まれたか確認します。

同梱ファイルadvanced.md

詳細

React Router

詳細な知識:React Router v6+ のパターンとデータ読み込みに関する包括的なドキュメントは、technology: react、topic: router を指定して mcp__documentation__fetch_docs を使用してください。

完全なリファレンス:データ読み込み(v6.4+)、アクション、コード分割、ルート設定、エラー処理、スクロール復元、モーダルルート、TypeScript との統合については、advanced.md を参照してください。

基本設定

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>
  );
}

ナビゲーション

Link コンポーネント
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>
  );
}
プログラムによるナビゲーション
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>
  );
}

ルートパラメーター

動的セグメント
<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>
  );
}
オプションのセグメント
<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>;
}

クエリパラメーター

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>
  );
}

ネストされたルート

// 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>
  );
}
相対リンク
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>
  );
}

保護されたルート

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>

ベストプラクティス

  • 共通レイアウトにはネストされたルートを使用します
  • データの取得にはローダーを使用します(v6.4+)
  • 適切なエラーバウンダリーを実装します
  • ネストされたルートでは相対リンクを使用します
  • ルートコンポーネントを遅延読み込みします
  • ユーザーの意図(ホバー)に応じて事前読み込みします
  • ローダーが利用できる場合は、useEffect 内でデータを取得しないでください
  • パスをハードコードせず、相対ナビゲーションを使用します
  • 読み込み状態の処理を忘れないでください

このスキルを使用しない場合

  • Next.js アプリケーション - 代わりに Next.js App Router または Pages Router を使用します
  • サーバーサイドルーティング - Express など、フレームワーク固有のルーティングを使用します
  • 単純な条件付きレンダリング - 基本的な表示/非表示のロジックには react スキルを使用します
  • 静的サイト - ルーティングライブラリが必要かどうかを検討してください

アンチパターン

アンチパターン問題解決策
ローダーを利用できるのに useEffect 内で取得する読み込みが連鎖し、UX が低下しますローダー関数を使用します
絶対パスをハードコードするリファクタリングが難しく、ネストされたルートが動作しなくなります相対パスを使用します
読み込み状態を処理しないUX が低下しますuseNavigation または Suspense を使用します
エラーバウンダリーがないルートのエラーでアプリがクラッシュしますルートに errorElement を追加します
ルートを遅延読み込みしない初期バンドルが大きくなりますルートに React.lazy() を使用します
インデックスをルートのキーとして使う動作が不正になりますルートにキーを使用しないでください
404 の処理を忘れる空白ページになるかクラッシュしますpath="*" のキャッチオールルートを追加します

トラブルシューティング(クイックガイド)

問題考えられる原因修正方法
ルートが一致しないパス構文が正しくないパスの定義を確認し、正確なパスを使用します
リンクが動作しないto プロパティが正しくないパスが / で始まっているか、相対パスであることを確認します
パラメーターが undefined になる間違ったフックを使用しているルートパラメーターには useParams() を使用します
ナビゲーションが動作しない間違ったフックを使用しているプログラムによるナビゲーションには useNavigate() を使用します
ネストされたルートが表示されないOutlet がない親コンポーネントに を追加します
ローダーが呼び出されないRouterProvider ではなく Routes を使用しているローダーとともに createBrowserRouter を使用します
保護されたルートが動作しないリダイレクトロジックが正しくない認証状態と Navigate コンポーネントを確認します

リファレンスドキュメント

コメント