# Pathrule Pattern: React Router 7 (1.0.0)
# ::pathrule:package:react-router

### [RULE] Load and mutate through loaders and actions  (path: /app/routes)
<!-- scope: folder | priority: high | advisory -->

In framework mode, route data and mutations live on the route module, not in component effects.

- Read data with `loader` (server) or `clientLoader` (browser); never fetch in `useEffect` for route data.
- Mutate with `action` / `clientAction` submitted via `<Form>` or `useSubmit`, not `fetch` in click handlers.
- After an action resolves, all page loaders revalidate automatically. Do not manually refetch.
- Put server-only secrets and DB calls in `loader`/`action`; they are stripped from the client bundle.

---

### [RULE] Use generated Route types, not hand-written ones  (path: /app/routes)
<!-- scope: folder | priority: high | advisory -->

React Router codegen emits a typed `Route` namespace per route file; use it instead of casting.

- Import with `import type { Route } from './+types/route-name'` and type args as `Route.LoaderArgs`, `Route.ActionArgs`, `Route.ComponentProps`.
- Read `params`, `loaderData`, and `actionData` from those typed props rather than `useParams()` casts.
- Keep `react-router typegen` (or `dev`) running so `.react-router/types/` stays current; do not edit generated files.
- Define routes in `app/routes.ts` with the config helpers so codegen and the type map stay in sync.

---

### [MEMORY] Framework mode data flow and single-fetch  (path: /app)

Framework mode (the Remix-merged full-stack setup) drives the data lifecycle from route modules.

- One navigation triggers a single HTTP request (single-fetch) that resolves every matched route's loader together; avoid waterfalling per-component fetches.
- `clientLoader` can hydrate the initial SSR render by exporting `clientLoader.hydrate = true`; otherwise it runs on client navigations.
- Streaming defer happens by returning promises from a loader and resolving them with `<Await>` / `useAsyncValue` so the shell renders immediately.
- Stable on `react-router` 7.17.x; the legacy `react-router-dom` package is folded into `react-router`.

---

### [MEMORY] Prefetch, navigation, and progressive enhancement  (path: /app/routes)

Navigation and forms are built to work before and after hydration.

- Set `<Link prefetch="intent">` for hover/focus prefetch, `"viewport"` for in-view, `"render"` for eager; prefetch uses `<link rel="prefetch">` tags.
- Use `<Form method="post">` so submissions work without JS; `useNavigation()` / `useFetcher()` give pending UI once hydrated.
- `useFetcher` handles non-navigation mutations (likes, inline edits) without changing the URL and still revalidates affected loaders.
- Throw `redirect()` or `data()` from loaders/actions for control flow instead of imperatively navigating in effects.

---

### [SKILL] react-router-review  (path: /)

---
name: react-router-review
description: Review a React Router 7 framework-mode route before merging. Use when adding or changing route modules, loaders, actions, or app/routes.ts.
---

# React Router 7 review

- [ ] Route data is read via `loader` / `clientLoader`, not `useEffect` fetches
- [ ] Mutations go through `action` / `clientAction` submitted with `<Form>` or `useFetcher`, not raw `fetch` in handlers
- [ ] Args and props use generated `Route.LoaderArgs` / `Route.ActionArgs` / `Route.ComponentProps` from `./+types/...`
- [ ] `params`, `loaderData`, `actionData` come from typed props, not `useParams()` casts
- [ ] Server-only code (secrets, DB) stays inside `loader`/`action` and out of the client bundle
- [ ] Route is registered in `app/routes.ts` and codegen (`.react-router/types/`) is up to date
- [ ] Redirects use `redirect()` thrown from loaders/actions, not imperative navigation in effects
- [ ] `<Link>` uses an appropriate `prefetch` mode for hot navigations
- [ ] Slow data is deferred with promises + `<Await>` instead of blocking the whole route
- [ ] Errors are handled with an exported `ErrorBoundary` / `meta` where needed
