このページは英語でのみご覧いただけます。
React Router 7
Pathruleルール3件 • メモリ2件 • スキル1件
React Router 7 merges Remix into a single multi-strategy router with a full framework mode for SSR, data loading, and mutations. This pattern keeps your data flow on loaders and actions, your routes type-safe through codegen, and your navigation fast with single-fetch and prefetching. It is tuned for the 7.17+ API surface and the framework-mode conventions teams ship in 2026.
推奨されるパスの配置
Pathruleは各要素を対応するパスに配置するため、アシスタントはそれが属する場所でだけ参照します。これはインポート時に適用されるスコープで、ワークスペースで調整できます。
/ ワークスペースのルート
react-router-review
app/
Keep the route config and codegen in sync
Framework mode data flow and single-fetch
Middleware and request context (v8_middleware)
routes/
Load and mutate through loaders and actions
Use generated Route types, not hand-written ones
ルール
3Load and mutate through loaders and actions/app/routes高助言Route data comes from loaders; mutations go through actions submitted with Form or useFetcher, never useEffect or ad-hoc fetch.
| 1 | In framework mode, route data and mutations live on the route module, not in component effects. |
| 2 | |
| 3 | - Read data with `loader` (server) or `clientLoader` (browser); never fetch route data in `useEffect`. |
| 4 | - Mutate with `action` / `clientAction` submitted via `<Form method="post">` or `useSubmit`, not `fetch` in click handlers. `<Form>` works before hydration, so submissions degrade gracefully without JS. |
| 5 | - After an action resolves, every matched route loader revalidates automatically. Do not manually refetch. If you see stale data, check that a `shouldRevalidate` export is not returning `false` and blocking the re-run. |
| 6 | - Use `useFetcher` for non-navigation mutations (likes, inline edits, autosave): it submits to an action and revalidates affected loaders without changing the URL. |
| 7 | - For control flow, `throw redirect("/path")` from a loader/action instead of navigating imperatively in an effect. |
| 8 | - Put server-only secrets and DB calls inside `loader`/`action`; that code is stripped from the client bundle. `clientLoader`/`clientAction` ship to the browser, so never put secrets there. |
Use generated Route types, not hand-written ones/app/routes高助言Import the per-route Route namespace for params, loaderData, and actionData typing; never edit generated files.
| 1 | React Router codegen emits a typed `Route` namespace per route file; use it instead of casting. |
| 2 | |
| 3 | - Import with `import type { Route } from "./+types/<route-file>"` and type handlers as `Route.LoaderArgs`, `Route.ClientLoaderArgs`, `Route.ActionArgs`, `Route.ComponentProps`, `Route.ErrorBoundaryProps`, `Route.HydrateFallbackProps`. |
| 4 | - The `+types/<name>` segment must mirror the route file name exactly, including `$` params and `.` separators (for example `./+types/posts.$id`). A mismatch is the most common "types are missing/wrong" cause. |
| 5 | - Read `params`, `loaderData`, and `actionData` from the typed props rather than `useParams()` casts; `params` is typed from the route pattern and `loaderData` is inferred from the loader return. |
| 6 | - Generated declarations live in `.react-router/types/`; they require `rootDirs` in `tsconfig.json` to resolve as if adjacent to the route. Keep `react-router dev` (or `react-router typegen --watch`) running so they stay current. Never hand-edit generated files and do not commit them. |
Keep the route config and codegen in sync/app中助言Pick one routing strategy; an app/routes.ts disables file-based convention unless you explicitly spread it back in.
| 1 | Framework-mode routing is driven by `app/routes.ts`, and the codegen depends on it being correct. |
| 2 | |
| 3 | - Define routes with the config helpers: `import { type RouteConfig, route, index, layout, prefix } from "@react-router/dev/routes"`. |
| 4 | - Once `app/routes.ts` exists, the file-system convention is OFF by default. You must declare every route, or routes silently 404. To keep convention-based discovery, spread it back in explicitly: `import { flatRoutes } from "@react-router/fs-routes"` then `export default [route("/", "./home.tsx"), ...(await flatRoutes())] satisfies RouteConfig`. |
| 5 | - Use `layout(file, children)` to nest UI without adding a URL segment, and `prefix(path, routes)` to add a path prefix without a new route module. Do not fake these with empty path segments. |
| 6 | - Every route module referenced in `routes.ts` must exist and export a `default` component (or be a pure layout/resource route); a dangling reference breaks typegen for the whole app. |
メモリ
2Framework mode data flow and single-fetch/appHow loaders, actions, revalidation, single-fetch, and deferred streaming fit together in RR7 framework mode.
| 1 | Framework mode (the Remix-merged full-stack setup) drives the data lifecycle from route modules. We are on `react-router` 7.17.x; `react-router-dom` is folded into `react-router`, so import everything from `react-router`. |
| 2 | |
| 3 | - One navigation triggers a single HTTP request (single-fetch) that resolves every matched route's loader together. Avoid waterfalling per-component fetches; co-locate data needs on the route loaders. |
| 4 | - On initial load/SSR the server `loader` runs; on client navigations the server loader is called via an automatic browser fetch. `clientLoader` runs only on the client unless you opt it into hydration. |
| 5 | - To run a `clientLoader` during hydration, export `clientLoader.hydrate = true as const` and provide a `HydrateFallback` component to render while it runs. |
| 6 | - Stream slow data: return a promise from a loader and render it with `<Await>` + `<Suspense>` (or `useAsyncValue`) so the shell paints immediately. Loader serialization also handles Dates, Maps, Sets, and promises, not just primitives. |
| 7 | - Single-fetch merges loader responses; when multiple matched loaders set headers, the deepest matching route wins. Set response headers from the leaf loader/action that owns them. |
| 8 | |
| 9 | See /app/routes for the load/mutate and generated-types rules, and the middleware memory at /app for the request-pipeline layer. |
Middleware and request context (v8_middleware)/appRR7 middleware runs before loaders/actions for auth, logging, and shared context; it is behind a future flag with a strict next() contract.
| 1 | React Router 7.17 ships middleware behind a future flag; it is the canonical place for auth, logging, and seeding per-request context. It is slated to become default in v8, so the API is stable enough to adopt now. |
| 2 | |
| 3 | - Enable it in `react-router.config.ts`: `export default { future: { v8_middleware: true } } satisfies Config`. In data mode (`createBrowserRouter`) you also augment the `Future` interface via `declare module "react-router"`. |
| 4 | - A route exports `middleware: Route.MiddlewareFunction[]` (server) and/or `clientMiddleware: Route.ClientMiddlewareFunction[]`. Each entry receives `({ request, context }, next)` and runs before that route's loader/action. |
| 5 | - Contract: call `await next()` to continue the chain; on the SERVER you must return the response (`return await next()`), and post-`next()` code runs after handlers (for timing, header rewriting). On the client `next()` is optional. `next()` may be called at most once and never throws; thrown errors route to the nearest `ErrorBoundary`. |
| 6 | - Share data through typed context, not module globals: `const userCtx = createContext<User | null>(null)`, then `context.set(userCtx, user)` in middleware and `context.get(userCtx)` in downstream middleware/loaders. With a custom server, return a `new RouterContextProvider()` from `getLoadContext`. |
| 7 | - Auth pattern: in middleware, load the session and `throw redirect("/login")` when missing, otherwise `context.set(userCtx, user)` so every loader on the route reads an authenticated user without re-checking. |
| 8 | |
| 9 | See /app for the single-fetch data-flow memory and /app/routes for the loader/action rules that consume this context. |
スキル
1react-router-review/rootPre-merge checklist for React Router 7 framework mode routes, loaders, actions, and middleware.
| 1 | --- |
| 2 | name: react-router-review |
| 3 | description: Review a React Router 7 framework-mode change before merging. Use when adding or changing route modules, loaders, actions, middleware, or app/routes.ts. |
| 4 | --- |
| 5 | |
| 6 | # React Router 7 review |
| 7 | |
| 8 | ## Data and mutations |
| 9 | - [ ] Route data is read via `loader` / `clientLoader`, not `useEffect` fetches |
| 10 | - [ ] Mutations go through `action` / `clientAction` submitted with `<Form>` or `useFetcher`, not raw `fetch` in handlers |
| 11 | - [ ] No manual refetch after an action; rely on automatic revalidation (check any `shouldRevalidate` does not block needed loaders) |
| 12 | - [ ] `useFetcher` is used for non-navigation mutations (likes, inline edits) instead of changing the URL |
| 13 | - [ ] Slow data is deferred with a returned promise + `<Await>` / `<Suspense>` instead of blocking the whole route |
| 14 | - [ ] Redirects use `throw redirect()` from loaders/actions, not imperative navigation in effects |
| 15 | |
| 16 | ## Type safety |
| 17 | - [ ] Args and props use generated `Route.LoaderArgs` / `Route.ActionArgs` / `Route.ComponentProps` from `./+types/...` |
| 18 | - [ ] The `+types/<name>` import path mirrors the route file name exactly (including `$` params and `.` separators) |
| 19 | - [ ] `params`, `loaderData`, `actionData` come from typed props, not `useParams()` casts |
| 20 | - [ ] No generated files (`.react-router/types/`) were hand-edited or committed |
| 21 | |
| 22 | ## Routing config |
| 23 | - [ ] New route is registered in `app/routes.ts` via `route` / `index` / `layout` / `prefix` (or covered by a spread `flatRoutes()`) |
| 24 | - [ ] Every referenced route module exists and exports a `default` (or is a deliberate layout/resource route) |
| 25 | |
| 26 | ## Middleware and security |
| 27 | - [ ] Server-only code (secrets, DB) stays inside `loader` / `action` / `middleware`, never in `clientLoader` / `clientAction` |
| 28 | - [ ] Middleware calls `await next()` and returns its response on the server; shared state goes through `createContext` + `context.set/get`, not module globals |
| 29 | - [ ] Auth/redirect checks live in `middleware` (or a loader) rather than being duplicated per component |
| 30 | |
| 31 | ## Resilience |
| 32 | - [ ] `<Link>` uses an appropriate `prefetch` mode (`intent` / `viewport` / `render`) for hot navigations |
| 33 | - [ ] Route exports an `ErrorBoundary` (and `meta` where needed) for failure and SEO paths |
このパターンを使う理由
Agents write React Router 7 like v6 SPAs, fetching in effects and ignoring loaders, actions, and generated route types.
対象:Teams building full-stack React apps on React Router 7 framework mode
アシスタントが次のことをしないようにします。
- Fetching data in useEffect instead of route loaders
- Hand-typing route params and loaderData instead of using generated Route types
- Mutating data with fetch in event handlers instead of route actions
- ライセンス
- Apache-2.0
- バージョン
- 1.0.1
- 更新日
- 2026-08-25