本文へ移動
cccskills
無料GitHub で公開

react-routing

Routing libraries for React SPAs: React Router v6/v7 (most common), TanStack Router (typed, modern), wouter (minimal). Detect what's installed and apply matching patterns. Lazy loading, navigation guards, typed params. Use this skill to: - Configure routes (declarative or file-based). - Use navigation hooks (useNavigate, useParams, useSearchParams). - Lazy-load routes for code splitting. - Implement protected routes / auth guards. - Type-safe params via Zod or framework's built-ins. Do NOT use this skill for: - General React conventions (see react-conventions). - State management (see react-state-management). - Form handling (see react-forms). - Next.js routing (different model — see nextjs-plugin).

インストール方法を見る

含まれるファイル(1)

  • SKILL.md9.6 KB

SKILL.md(原文)

インストールする前に、エージェントに与えられる指示の中身を確認できます。

React Routing Patterns

Choose the routing library based on what's already in package.json. Don't introduce a new one without BA approval.

Detection

Marker (in dependencies)Library
react-router-domReact Router v6 (≤6.x) or v7
@tanstack/react-routerTanStack Router
wouterwouter (minimal alternative)
(none)Single-page; introduce only if BA spec adds multi-page

React Router v6 / v7

The de-facto standard. v7 unified react-router-dom and the framework features; for SPA usage the API is similar.

Declarative routes (most common)

// src/main.tsx
import { createBrowserRouter, RouterProvider } from 'react-router-dom';
import App from './App';
import UsersList from './pages/UsersList';
import UserDetail from './pages/UserDetail';
import Login from './pages/Login';
import NotFound from './pages/NotFound';

const router = createBrowserRouter([
  {
    path: '/',
    element: <App />,
    errorElement: <NotFound />,
    children: [
      { index: true, element: <Home /> },
      { path: 'users', element: <UsersList /> },
      { path: 'users/:id', element: <UserDetail /> },
      { path: 'login', element: <Login /> },
    ],
  },
]);

ReactDOM.createRoot(document.getElementById('root')!).render(
  <RouterProvider router={router} />
);

<App /> is the layout; <Outlet /> inside renders the matched child route:

// src/App.tsx
import { Outlet } from 'react-router-dom';

export default function App() {
  return (
    <div>
      <Header />
      <main><Outlet /></main>
      <Footer />
    </div>
  );
}

Navigation hooks

import { Link, NavLink, useNavigate, useParams, useSearchParams, useLocation } from 'react-router-dom';

// Declarative — Link or NavLink
<Link to="/users">Users</Link>
<NavLink to="/users" className={({ isActive }) => isActive ? 'active' : ''}>Users</NavLink>

// Programmatic
const navigate = useNavigate();
navigate('/users');                          // push
navigate('/users', { replace: true });       // replace
navigate(-1);                                 // back

// Params from dynamic segments
const { id } = useParams<{ id: string }>();

// Search params (query string)
const [searchParams, setSearchParams] = useSearchParams();
const filter = searchParams.get('filter') ?? 'all';
setSearchParams({ filter: 'active' });

// Current location
const location = useLocation();
console.log(location.pathname, location.search, location.hash);

Loaders and actions (data router APIs)

In React Router v6.4+ / v7, route loaders fetch data before render:

// src/routes/users.tsx
import { LoaderFunction, useLoaderData } from 'react-router-dom';

export const loader: LoaderFunction = async () => {
  const res = await fetch('/api/users');
  if (!res.ok) throw new Response('Failed', { status: 500 });
  return res.json();
};

export function UsersList() {
  const users = useLoaderData() as User[];
  return <ul>{users.map((u) => <li key={u.id}>{u.name}</li>)}</ul>;
}

Wire in route config:

{ path: 'users', element: <UsersList />, loader: usersLoader }

For mutations:

import { ActionFunction, redirect, useActionData } from 'react-router-dom';

export const action: ActionFunction = async ({ request }) => {
  const formData = await request.formData();
  // ... validate, save
  return redirect('/users');
};

Loaders/actions are an alternative to TanStack Query — pick one per project. For most projects with TanStack Query, skip loaders; use useQuery inside the route component.

Lazy-loaded routes

import { lazy } from 'react';

const UsersList = lazy(() => import('./pages/UsersList'));

// In route config
{
  path: 'users',
  element: (
    <Suspense fallback={<Spinner />}>
      <UsersList />
    </Suspense>
  ),
}

For file-based code splitting, route config can use lazy loader:

{ path: 'users', lazy: () => import('./routes/users') }

The imported module exports { Component, loader, action }.

Protected routes (auth guards)

// src/routes/RequireAuth.tsx
import { Navigate, Outlet, useLocation } from 'react-router-dom';
import { useAuth } from '@/hooks/useAuth';

export function RequireAuth() {
  const { user } = useAuth();
  const location = useLocation();
  if (!user) return <Navigate to="/login" state={{ from: location }} replace />;
  return <Outlet />;
}

Wrap protected routes:

{
  element: <RequireAuth />,
  children: [
    { path: 'dashboard', element: <Dashboard /> },
    { path: 'settings', element: <Settings /> },
  ],
}

Type-safe params with Zod

import { useParams } from 'react-router-dom';
import { z } from 'zod';

const ParamsSchema = z.object({ id: z.string().uuid() });

function UserDetail() {
  const params = useParams();
  const parsed = ParamsSchema.safeParse(params);
  if (!parsed.success) throw new Error('Invalid params');
  const { id } = parsed.data; // string (UUID)
  // ...
}

For library-level type safety, see TanStack Router below.

TanStack Router

Typed, modern. Code-based or file-based routing. Built-in search-param parsing and validation.

File-based setup

// src/routeTree.gen.ts (generated by @tanstack/router-plugin)

// src/routes/__root.tsx
import { createRootRoute, Outlet } from '@tanstack/react-router';

export const Route = createRootRoute({
  component: () => (
    <div>
      <Header />
      <Outlet />
    </div>
  ),
});

// src/routes/users.tsx
import { createFileRoute } from '@tanstack/react-router';

export const Route = createFileRoute('/users')({
  component: UsersPage,
  loader: () => fetchUsers(),
});

function UsersPage() {
  const users = Route.useLoaderData();
  return <ul>{users.map((u) => <li key={u.id}>{u.name}</li>)}</ul>;
}

// src/routes/users.$id.tsx — dynamic segment
export const Route = createFileRoute('/users/$id')({
  parseParams: (params) => ({ id: z.string().uuid().parse(params.id) }),
  component: UserDetail,
});

Route.useParams() returns the parsed (typed) params — no runtime check needed at the consumer.

Search params validation

export const Route = createFileRoute('/users')({
  validateSearch: z.object({
    filter: z.enum(['all', 'active', 'archived']).default('all'),
    page: z.number().int().min(1).default(1),
  }),
  component: UsersPage,
});

// In component
const { filter, page } = Route.useSearch();

Type-safe, validated search params at the route level.

Navigation

import { Link, useNavigate } from '@tanstack/react-router';

<Link to="/users" search={{ filter: 'active' }}>Active users</Link>;

const navigate = useNavigate();
navigate({ to: '/users/$id', params: { id: '123' }, search: { tab: 'overview' } });

Navigation is fully type-checked — wrong path or missing param is a compile error.

wouter

Minimal alternative (pnpm add wouter). ~3 KB. Pattern-based.

import { Route, Switch, Link, useLocation } from 'wouter';

function App() {
  return (
    <Switch>
      <Route path="/"><Home /></Route>
      <Route path="/users"><UsersList /></Route>
      <Route path="/users/:id">{(params) => <UserDetail id={params.id} />}</Route>
      <Route><NotFound /></Route>
    </Switch>
  );
}

const [location, setLocation] = useLocation();
setLocation('/users');

Good for very small apps. Misses nested routes with shared layouts (build them via composition).

Code splitting strategy

Routes are the natural boundary. Don't over-split:

  • Each top-level route → split.
  • Heavy modal/wizard inside a route → split.
  • Small page → don't bother.

For React Router:

{ path: 'users', lazy: () => import('./routes/users') }

For TanStack Router with file-based routes — splitting is built into the plugin.

Layout patterns

Layouts compose via parent routes:

// React Router
{
  element: <DashboardLayout />,
  path: '/dashboard',
  children: [
    { index: true, element: <DashboardHome /> },
    { path: 'analytics', element: <Analytics /> },
    { path: 'settings', element: <Settings /> },
  ],
}

<DashboardLayout /> renders <Outlet /> for children. Persists across navigation within the layout.

Anti-patterns

  • ❌ Mixing <a href="/internal"> with <Link> — full page reload defeats SPA benefits.
  • ❌ Storing data already in URL params in component state too — keep ONE source of truth.
  • ❌ Reading window.location.search directly — use useSearchParams or framework hook.
  • ❌ Programmatic navigation deep in business logic — pass a callback or use a hook at the page level.
  • ❌ Loaders that fetch data already cached by TanStack Query — pick one strategy per project.
  • ❌ Forgetting to wrap lazy-loaded routes in <Suspense> — error boundary catches the thrown promise oddly.
  • ❌ useNavigate inside a useEffect for redirects — use loaders or <Navigate> instead, or run on event handlers.
  • ❌ Long route trees in one file — split by feature.

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

同じリポジトリのスキル

概要と使いどころ

Angular 18-21 project structure, standalone components vs NgModule, control flow (@if/@for/@switch + *ngIf/*ngFor legacy), decorators, dependency injection (inject() function), lifecycle hooks, pipes, Angular Universal SSR pointer. Use this skill to: - Detect project style (standalone vs NgModule) and apply matching patterns. - Pick correct decorators and DI approach. - Use modern control flow (@if/@for/@switch) in Angular 17+ projects. - Apply `inject()` function over constructor injection where appropriate. - Wire bootstrap correctly (bootstrapApplication for standalone, AppModule for legacy). Do NOT use this skill for: - State management (see angular-state-and-rx). - Routing (see angular-routing). - Forms (see angular-forms). - Testing (see angular-testing).

日本語の概要は準備中です。原文の説明を表示しています。

AratKruglik/claude-sdlc362026年9月21日 更新

Angular forms: Reactive Forms (preferred — typed FormGroup/FormControl since Angular 14, FormBuilder, custom + async validators, FormArray, multi-step) and Template-driven (`[(ngModel)]` + FormsModule). Validation strategies, server error mapping, accessibility. Use this skill to: - Build Reactive Forms with typed FormGroup/FormControl. - Use FormBuilder для concise syntax. - Implement custom synchronous and async validators. - Wire FormArray for dynamic field lists. - Map server errors back to form fields. - Pick Reactive vs Template-driven (prefer Reactive). Do NOT use this skill for: - General conventions (see angular-conventions). - State management beyond forms (see angular-state-and-rx). - Routing (see angular-routing). - Testing forms (see angular-testing).

日本語の概要は準備中です。原文の説明を表示しています。

AratKruglik/claude-sdlc362026年9月21日 更新

Angular Router (built-in `@angular/router`) — route configuration for standalone and NgModule projects, functional guards (Angular 14.1+), lazy loading, route resolvers, typed params via signals/observables, programmatic navigation, route data and meta. Use this skill to: - Configure routes (standalone-style or NgModule-style). - Use functional guards (canActivate as function, preferred over class-based in 17+). - Lazy-load components or feature modules. - Implement auth guards via route meta + functional guards. - Read params/queries via `inject(ActivatedRoute)` + signals or RxJS. Do NOT use this skill for: - General conventions (see angular-conventions). - State management (see angular-state-and-rx). - Forms (see angular-forms). - Testing routes (see angular-testing).

日本語の概要は準備中です。原文の説明を表示しています。

AratKruglik/claude-sdlc362026年9月21日 更新

State management for Angular 18-21: signals (signal/computed/effect), services-as-state, NgRx Store + Effects + Selectors, NgRx Component Store, NgRx Signals (newer signal-based store). RxJS essentials — operators, async pipe, takeUntilDestroyed, signal/observable interop. Use this skill to: - Pick the right state tool (signals / services / NgRx variant / vue-query equivalent). - Use signals correctly (signal/computed/effect — when each). - Build a Pinia-style service-as-state singleton. - Set up NgRx Store + Effects + Selectors. - Use RxJS without leaking subscriptions (async pipe, takeUntilDestroyed, Subject patterns). - Bridge signals ↔ observables via toSignal / toObservable. Do NOT use this skill for: - General Angular conventions (see angular-conventions). - Routing state (see angular-routing). - Form state (see angular-forms). - Testing state (see angular-testing).

日本語の概要は準備中です。原文の説明を表示しています。

AratKruglik/claude-sdlc362026年9月21日 更新

Testing Angular 18-21: TestBed, component harnesses (@angular/cdk/testing), Karma+Jasmine (default historical) vs Jest (jest-preset-angular, modern), Angular Testing Library (RTL-style). HttpClient mocking via HttpTestingController. NgRx Effects testing. Cypress / Playwright e2e. Use this skill to: - Detect runner (Karma+Jasmine vs Jest) and configure correctly. - Write component tests with TestBed. - Use component harnesses for Material / custom UI components. - Mock HttpClient via provideHttpClientTesting + HttpTestingController. - Test signal-based inputs with componentRef.setInput(). - Test NgRx Effects with provideMockActions. Do NOT use this skill for: - General Angular conventions (see angular-conventions). - Routing patterns broadly (see angular-routing — covers testing routes briefly). - Form patterns broadly (see angular-forms).

日本語の概要は準備中です。原文の説明を表示しています。

AratKruglik/claude-sdlc362026年9月21日 更新

Shared conventions for every SDLC development-phase architect agent: hard rules, code quality bar, workflow steps (superpowers invocation, spec reading, codebase exploration, verification), and the report/compact-summary contract. Architects load this skill first, then apply their stack-specific instructions on top.

日本語の概要は準備中です。原文の説明を表示しています。

AratKruglik/claude-sdlc362026年9月21日 更新

AratKruglik のスキルをすべて見る

このスキルの問題を報告する