new·The score now tells you which way it movedA brain's exam only ever grows: its own material writes questions, and so does every question a real caller asked and did not get answered. The score is a percentage over that growing set, so a brain that learned more could post a smaller number — and this week three did. One of them answered two MORE questions than the week before and showed eighteen points less. Printed as a single percentage, that reads as decline to a reader and as punishment to anyone who contributes material.all news →
mozg.beta
Sign in

React Router · Guides · all subjects

routing

157 notes in this subject, read out of this brain and free to use. This is page 3 of 3.

Enable SPA Mode in React Router

To enable Single Page App Mode in React Router Framework, set `ssr: false` in the `react-router.config.ts` file. This disables runtime server rendering and generates an `index.html` at build time that you can serve and hydrate as a SPA.

ssr:false only disables runtime server rendering

Setting `ssr: false` only disables runtime server rendering. React Router still performs server rendering of your root route at build time to generate the `index.html` file. Your project still needs a dependency on `@react-router/node` and routes must be SSR-safe, meaning you cannot call `window` or other browser-only APIs during the initial render.

HydrateFallback component in root route

Add a `HydrateFallback` component to your root route to render a loading UI into the `index.html` at build time. This loading UI will be shown to users immediately while the SPA is loading and hydrating, rather than displaying an empty `<div>`.

Root loader example with HydrateFallback

Example showing how to use a root `loader` with `HydrateFallback`. The loader is called at build time and its data is available to `HydrateFallback` via the `loaderData` prop: ```tsx import { Route } from "./+types/root"; export async function loader() { return { version: await getVersion(), }; } export function HydrateFallback({ loaderData, }: Route.ComponentProps) { return ( <div> <h1>Loading version {loaderData.version}...</h1> <AwesomeSpinner /> </div> ); } ```

Loader restrictions in SPA Mode

You cannot include a `loader` in any routes other than the root route when using SPA Mode, unless you are pre-rendering those pages separately.

Use clientLoader and clientAction in SPA Mode

With server rendering disabled in SPA Mode, you can use `clientLoader` and `clientAction` to manage route data and mutations on the client side. These are available in all routes except the root route.

clientLoader and clientAction example

Example showing how to use `clientLoader` and `clientAction` in SPA Mode: ```tsx import { Route } from "./+types/some-route"; export async function clientLoader({ params, }: Route.ClientLoaderArgs) { let data = await fetch(`/some/api/stuff/${params.id}`); return data; } export async function clientAction({ request, }: Route.ClientActionArgs) { let formData = await request.formData(); return await processPayment(formData); } ```

Configure host to redirect all URLs to index.html

After running `react-router build`, deploy the `build/client` directory to your static host. Configure your host to direct all URLs to the `index.html` file. Some hosts do this by default, but others require configuration. For example, some hosts support a `_redirects` file with the entry: `/* /index.html 200`. If you're getting 404s at valid routes, you likely need to configure your host.

SPA Mode configuration example

Example showing how to set `ssr: false` in `react-router.config.ts`: ```ts import { type Config } from "@react-router/dev/config"; export default { ssr: false, } satisfies Config; ```

useMatches and handle for dynamic UI elements

You can build dynamic UI elements like breadcrumbs based on your route hierarchy using the useMatches hook and handle route exports. Routes contribute metadata through the handle export that can be rendered by ancestor components.

handle export property naming

The handle export can have any property name you choose based on your use case. For breadcrumbs, the example uses a breadcrumb property, but you can name it whatever makes sense for your application.

Defining breadcrumb in parent route handle

In a parent route file, export a handle object with a breadcrumb function that returns a React component. For example: export const handle = { breadcrumb: () => <Link to="/parent">Some Route</Link> };

Defining breadcrumb in child route handle

Child routes can also define breadcrumbs in their handle export. For example: export const handle = { breadcrumb: () => <Link to="/parent/child">Child Route</Link> };

Rendering breadcrumbs in ancestor component

In an ancestor component like a root layout, use the useMatches hook to get all route matches. Filter matches where match.handle and match.handle.breadcrumb exist, then map over them calling the breadcrumb function and passing the match object. This renders all collected breadcrumbs in an ordered list.

Accessing route data in breadcrumb function

The match object passed to each breadcrumb function provides access to match.data (from loaders) and other route information. This allows you to create dynamic breadcrumbs based on your route's data.

Pattern for routes contributing metadata to ancestors

The handle export combined with useMatches enables routes to contribute to rendering processes higher up the component tree than their actual render point. This pattern works for any scenario where routes need to provide additional information to their ancestors, not just breadcrumbs.

GitHub webhook receiver example with signature validation

Resource routes can handle webhooks. This example shows how to create a GitHub webhook receiver that validates the webhook signature using HMAC-SHA256. The action function checks that the request method is POST (returns 405 if not), extracts the payload, retrieves the X-Hub-Signature-256 header, generates a signature using crypto.createHmac with the GITHUB_WEBHOOK_SECRET environment variable, and compares it with the received signature (returns 401 if signatures don't match). If validation passes, the webhook can be processed (such as enqueueing a background job) and returns a success response.

Webhook signature validation header for GitHub

GitHub webhooks send the signature in the X-Hub-Signature-256 request header. The signature is generated by GitHub using HMAC-SHA256 with the webhook secret, formatted as 'sha256=' followed by the hex digest of the JSON stringified payload.

CSS contain layout property for view transitions

Use `contain: layout` CSS property on elements that will use view transitions to optimize animation performance. For images in view transition examples, both the `.image-list img { contain: layout; }` and `.image-detail img { contain: layout; }` use this property.

Enable view transitions on Link and Form components

Add the `viewTransition` prop to Link, NavLink, or Form components to automatically wrap the navigation update in `document.startViewTransition()`. This provides a basic cross-fade animation between pages without additional CSS. Example: `<Link to="/about" viewTransition>About</Link>`

useViewTransitionState hook for conditional transition names

The `useViewTransitionState(href)` hook provides the transition state for a specific route. It returns a boolean indicating whether a transition is occurring to that route. This allows you to conditionally set `view-transition-name` CSS properties based on whether a transition is active, enabling precise control over which elements animate during navigation.

NavLink render props for view transition control

NavLink components can use a render prop pattern with `{ isTransitioning }` to conditionally apply `view-transition-name` styles. When `isTransitioning` is true, set the `view-transition-name` property; when false, set it to "none". This provides an alternative to the `useViewTransitionState` hook for controlling transitions.

View transition names for matching elements across routes

Elements that should transition smoothly between routes must have matching `view-transition-name` CSS properties in both the source and destination routes. For example, an image in a gallery list and the same image in a detail view should both have `view-transition-name: image-expand` to animate smoothly between them.

Image gallery view transition example

Example showing how to create an image gallery with view transitions. The gallery route uses NavLink components with `viewTransition` prop wrapping images and titles. The detail route displays the selected image with matching `view-transition-name` CSS properties (image-expand for the image, image-title for the title). The CSS uses `.image-list a.transitioning img { view-transition-name: image-expand; }` and `.image-detail img { view-transition-name: image-expand; }` to match transition names across routes.

Enable view transitions with useNavigate

When using programmatic navigation with the `useNavigate` hook, pass the `viewTransition: true` option in the second argument to enable view transitions. Example: `navigate("/about", { viewTransition: true })`. This provides the same cross-fade animation as using the `viewTransition` prop on Link components.

Render existing App in catchall route

To restore your existing app during migration, update the catchall route to import and render your App component: import App from "./App"; then export default function Component() { return <App />; }

Incrementally migrate routes to route modules

After the initial setup, you can migrate routes one at a time from your App component's Routes to route modules. Add the route to routes.ts pointing to a route module file (e.g., route("/about", "./pages/about.tsx")), then create the route module file with clientLoader and a default Component export.

Route module exports API

Route modules export an optional clientLoader function for data fetching and a required default Component function that receives loaderData as a prop.

Set up initial routes.ts with catchall route

Create src/routes.ts and export an array of RouteConfig. Use route("*?", "catchall.tsx") as a catchall route where * matches all URLs and ? makes it optional so it matches / as well.

Route module example with clientLoader

Example route module in src/routes/about.tsx: ```tsx export async function clientLoader() { return { title: "About", }; } export default function About() { let data = useLoaderData(); return <div>{data.title}</div>; } ```

Convert route modules to data router format

Create a convert helper function that takes a route module and transforms it to data router format. Extract clientLoader and clientAction as named exports and rename them to loader and action, extract the default export as Component, and spread remaining properties.

Routes configuration file format

Create src/routes.ts that exports a default array of route definitions satisfying RouteConfig type from @react-router/dev/routes. Use file: "./routes/path.tsx" instead of lazy: () => import().then(convert) to specify route modules.

Convert function example for route modules

Example convert function: ```tsx function convert(m: any) { let { clientLoader, clientAction, default: Component, ...rest } = m; return { ...rest, loader: clientLoader, action: clientAction, Component, }; } ```

Routes.ts configuration example

Example src/routes.ts: ```tsx import type { RouteConfig } from "@react-router/dev/routes"; export default [ { path: "/", file: "./routes/layout.tsx", children: [ { index: true, file: "./routes/home.tsx", }, { path: "about", file: "./routes/about.tsx", }, { path: "todos", file: "./routes/todos.tsx", children: [ { path: ":id", file: "./routes/todo.tsx", }, ], }, ], }, ] satisfies RouteConfig; ```

Enable future.v8_trailingSlashAwareDataRequests

In react-router.config.ts, add: export default { future: { v8_trailingSlashAwareDataRequests: true } } satisfies Config;

future.v8_trailingSlashAwareDataRequests preserves trailing slash semantics

Data requests for routes with and without trailing slashes could map to the same .data URL in v7 because trailing slashes were not considered. This flag preserves trailing slash semantics for data request URLs. For /a/b/c/, data requests change from /a/b/c.data to /a/b/c/_.data. Root data request changes from /_root.data to /_.data.

Update .data URL patterns for trailing slash awareness

When enabling future.v8_trailingSlashAwareDataRequests, if you have custom app, CDN, cache, or rewrite logic that matches .data request URLs, update it to handle the new trailing-slash-aware /_.data format. For routes with trailing slashes like /a/b/c/, data requests will be /a/b/c/_.data instead of /a/b/c.data.

Give your agent this brain