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 · Getting started · all subjects

routing/data-loading

47 notes, read out of this brain and free to use. Each one was extracted from a source and is re-checked against its exam.

Loaders execute before route component renders

When a user navigates between routes, the loaders are called before the route component is rendered. This ensures data is available when the component mounts.

useLoaderData usage example

Example of accessing loader data in a route component: ```tsx import { useLoaderData } from "react-router"; function MyRoute() { const { records } = useLoaderData(); return <div>{records.length}</div>; } ``` This shows importing useLoaderData and destructuring data from the loader function.

Route loader function provides data

Data is provided to route components from route loaders. The loader property accepts an async function that returns data. This data is returned to the route component and becomes available via the useLoaderData hook.

useLoaderData hook accesses route loader data

The useLoaderData hook from react-router retrieves data provided by a route's loader function. It must be imported from 'react-router' and called inside the route component to access the returned data object.

Route loader example with async data fetching

Example of setting up a route loader: ```tsx createBrowserRouter([ { path: "/", loader: async () => { // return data from here return { records: await getSomeRecords() }; }, Component: MyRoute, }, ]); ``` This shows a loader function that performs async operations and returns an object with data.

Loader data revalidation example

When a Form is submitted with method='post' to a route with both an action and loader, the action executes first, and then the loader is automatically revalidated. This ensures the component data stays in sync with server state changes.

Route Object loader

Route loaders provide data to route components before they are rendered. Loaders are async functions that receive a params argument and return data that is accessed in the component via useLoaderData().

Automatic loader revalidation conditions

A route loader is automatically revalidated when: its own route params change, any change to URL search params occurs, or after an action is called and returns a non-error status code.

Route Object shouldRevalidate

shouldRevalidate is a hook that enables you to opt in or out of the default revalidation behavior. By defining this function, you opt out of the default behavior completely and can manually control when loader data is revalidated for navigations and form submissions. The function receives ShouldRevalidateFunctionArgs and returns a boolean.

useLoaderData hook

Components can access data returned from a loader function using the useLoaderData hook imported from react-router.

Loader function with dynamic params

Route objects can define a loader function that receives an object with params property. The params object contains dynamic segments parsed from the URL. Example: loader: async ({ params }) => { let team = await fetchTeam(params.teamId); return { name: team.name }; }

Loader data type automatically generated

The type for the loaderData prop is automatically generated for type safety.

Serializable types supported by loaders

React Router tries to support the same set of serializable types that React permits server components to pass as props to client components. This includes primitive values like strings and numbers, promises, maps, sets, dates and more.

Using both loader and clientLoader together

loader and clientLoader can be used together. The loader will be used on the server for initial SSR (or pre-rendering) and the clientLoader will be used on subsequent client-side navigations. In the clientLoader, you can call serverLoader() to access data from the server loader.

Data provided by loader and clientLoader

Data is provided to the route component from loader and clientLoader. Loader data is automatically serialized from loaders and deserialized in components. In addition to primitive values like strings and numbers, loaders can return promises, maps, sets, dates and more.

clientLoader for client-side data fetching

clientLoader is used to fetch data on the client. This is useful for pages or full projects that you'd prefer to fetch data from the browser only. The HydrateFallback component is rendered while the client loader is running.

Client loader example with HydrateFallback

Example of clientLoader usage: ```tsx import type { Route } from "./+types/product"; export async function clientLoader({ params, }: Route.ClientLoaderArgs) { const res = await fetch(`/api/products/${params.pid}`); const product = await res.json(); return product; } export function HydrateFallback() { return <div>Loading...</div>; } export default function Product({ loaderData, }: Route.ComponentProps) { const { name, description } = loaderData; return ( <div> <h1>{name}</h1> <p>{description}</p> </div> ); } ```

Server loader for initial page loads and client navigations

When server rendering, loader is used for both initial page loads and client navigations. Client navigations call the loader through an automatic fetch by React Router from the browser to your server. The loader function is removed from client bundles so you can use server only APIs without worrying about them being included in the browser.

Server loader example

Example of server-side loader usage: ```tsx import type { Route } from "./+types/product"; import { fakeDb } from "../db"; export async function loader({ params }: Route.LoaderArgs) { const product = await fakeDb.getProduct(params.pid); return product; } export default function Product({ loaderData, }: Route.ComponentProps) { const { name, description } = loaderData; return ( <div> <h1>{name}</h1> <p>{description}</p> </div> ); } ```

Static data loading with pre-rendering

When pre-rendering, loaders are used to fetch data during the production build. The URLs to pre-render are specified in react-router.config.ts using the prerender function. When server rendering, any URLs that aren't pre-rendered will be server rendered as usual, allowing you to pre-render some data at a single route while still server rendering the rest.

Static loader example with prerender config

Example of static data loading: ```tsx export async function loader({ params }: Route.LoaderArgs) { let product = await getProductFromCSVFile(params.pid); return product; } ``` With prerender configuration in react-router.config.ts: ```ts import type { Config } from "@react-router/dev/config"; export default { async prerender() { let products = await readProductsFromCSVFile(); return products.map( (product) => `/products/${product.id}`, ); }, } satisfies Config; ```

Combined loader and clientLoader example

Example of using both loaders together: ```tsx import type { Route } from "./+types/product"; import { fakeDb } from "../db"; export async function loader({ params }: Route.LoaderArgs) { return fakeDb.getProduct(params.pid); } export async function clientLoader({ serverLoader, params, }: Route.ClientLoaderArgs) { const res = await fetch(`/api/products/${params.pid}`); const serverData = await serverLoader(); return { ...serverData, ...(await res.json()) }; } export default function Product({ loaderData, }: Route.ComponentProps) { const { name, description } = loaderData; return ( <div> <h1>{name}</h1> <p>{description}</p> </div> ); } ```

clientLoader.hydrate property for forced hydration

You can force the client loader to run during hydration and before the page renders by setting the hydrate property on the clientLoader function to true. In this situation you will want to render a HydrateFallback component to show a fallback UI while the client loader runs. Use `as const` for proper type inference.

clientLoader.hydrate example

Example of forcing client loader to run during hydration: ```tsx export async function loader() { /* ... */ } export async function clientLoader() { /* ... */ } // force the client loader to run during hydration clientLoader.hydrate = true as const; // `as const` for type inference export function HydrateFallback() { return <div>Loading...</div>; } export default function Product() { /* ... */ } ```

Route loader function

Route loaders provide data to route components before they are rendered. They are only called on the server when server rendering or during the build with pre-rendering. The loader function is async and returns data that becomes available to the route component via loaderData prop.

Route clientLoader function

clientLoader is called only in the browser and provides data to route components in addition to or in place of route loaders. It can call the server loader via the serverLoader parameter and/or fetch data on the client. It can participate in initial page load hydration by setting clientLoader.hydrate = true as const, which allows TypeScript to infer proper types for loaderData.

Route action function

Route actions allow server-side data mutations with automatic revalidation of all loader data on the page when called from Form, useFetcher, or useSubmit. When an action completes, all loaders on the page are automatically revalidated to update the data.

Route clientAction function

clientAction is like route actions but only called in the browser. It can perform client-side data mutations and can still call the server action if needed.

Route loader example

Example route loader: ```tsx export async function loader() { return { message: "Hello, world!" }; } export default function MyRoute({ loaderData }) { return <h1>{loaderData.message}</h1>; } ```

Route clientLoader example

Example route client loader: ```tsx export async function clientLoader({ serverLoader }) { // call the server loader const serverData = await serverLoader(); // And/or fetch data on the client const data = getDataFromClient(); // Return the data to expose through useLoaderData() return data; } ```

Route clientLoader with hydrate example

Example client loader that participates in hydration: ```tsx export async function clientLoader() { // ... } clientLoader.hydrate = true as const; ``` Using `as const` allows TypeScript to infer that clientLoader.hydrate is `true` instead of `boolean`, enabling React Router to derive correct types for loaderData.

Route action with Form example

Example route with action and Form: ```tsx // route("/list", "./list.tsx") import { Form } from "react-router"; import { TodoList } from "~/components/TodoList"; // this data will be loaded after the action completes... export async function loader() { const items = await fakeDb.getItems(); return { items }; } // ...so that the list here is updated automatically export default function Items({ loaderData }) { return ( <div> <List items={loaderData.items} /> <Form method="post" navigate={false} action="/list"> <input type="text" name="title" /> <button type="submit">Create Todo</button> </Form> </div> ); } export async function action({ request }) { const data = await request.formData(); const todo = await fakeDb.addItem({ title: data.get("title"), }); return { ok: true }; } ```

Route clientAction example

Example route client action: ```tsx export async function clientAction({ serverAction }) { fakeInvalidateClientSideCache(); // can still call the server action if needed const data = await serverAction(); return data; } ```

Data mode features and setup

Data mode moves route configuration outside of React rendering and adds data loading, actions, pending states and more with APIs like loader, action, and useFetcher. To use it, import createBrowserRouter and RouterProvider from react-router, create a router with route configuration, and wrap your app with RouterProvider.

Data mode example code

```tsx import { createBrowserRouter, RouterProvider, } from "react-router"; let router = createBrowserRouter([ { path: "/", Component: Root, loader: loadRootData, }, ]); ReactDOM.createRoot(root).render( <RouterProvider router={router} />, ); ``` This example shows how to set up Data mode with a router configuration array.

Framework mode Route Module API example

```ts import { Route } from "./+types/product.tsx"; export async function loader({ params }: Route.LoaderArgs) { let product = await getProduct(params.pid); return { product }; } export default function Product({ loaderData, }: Route.ComponentProps) { return <div>{loaderData.product.name}</div>; } ``` This example shows Framework mode Route Module API with type-safe params and loaderData.

When to use Data mode

Use Data Mode if you want data features but also want to have control over bundling, data, and server abstractions, or if you started a data router in v6.4 and are happy with it.

clientLoader for client-side data loading

Export an async `clientLoader()` function from a route module to load data on the client side. The function returns an object with data. React Router automatically keeps this data in sync with the UI. Usage: `export async function clientLoader() { const contacts = await getContacts(); return { contacts }; }` React Router generates types automatically through `Route.ComponentProps` for type safety.

loader function for server-side data fetching

Export an async `loader()` function (not `clientLoader`) from a route module to fetch data on the server. Usage: `export async function loader({ params }: Route.LoaderArgs) { const contact = await getContact(params.contactId); return { contact }; }` This is used when server-side rendering is enabled.

Throwing Response for error handling in loaders

In loader functions, throw a Response to handle errors (e.g., 404): `if (!contact) { throw new Response('Not Found', { status: 404 }); }`. This stops code execution and renders the error path instead. Components can then focus only on the happy path.

Accessing URL search params in loaders

In loader functions, access URL search parameters via: `const url = new URL(request.url); const q = url.searchParams.get('q');`. This allows filtering data based on query parameters from GET forms.

Route parameters in loader and action functions

Both loader and action functions receive `params` object containing dynamic route segments. For route `contacts/:contactId/edit`, params will have `params.contactId` with the matched value. Example: `export async function loader({ params }: Route.LoaderArgs) { const contact = await getContact(params.contactId); }`

fetcher.load() participates in revalidations

When a mutation is submitted in React Router, revalidation updates all active loaded data including route loaders and active fetcher.load() calls. This prevents fetchers from returning stale data after mutations. Fetchers can opt out of revalidation using the shouldRevalidate() method. This differs from Remix behavior and is categorized as a bug fix.

Request.signal replaces signal parameter

The signal parameter was removed from loaders and actions because the incoming Request object already has its own signal property. Developers should access revalidation signals via request.signal instead.

useRevalidator hook availability

React Router provides a useRevalidator() hook that was a long-requested feature. This hook allows manual triggering of data revalidation.

Data-aware router changes history lifecycle

In the data-aware router, the navigation flow differs by operation type. For PUSH/REPLACE operations: router.navigate → load data → update state → update history. For POP operations (back/forward buttons): update history → router.navigate → load data → update state. This means for PUSH/REPLACE the router informs history, but for POP, history informs the router. The URL only updates after data loading completes for PUSH/REPLACE, keeping users on the old page while data fetches.

shouldRevalidate API

The unstable_shouldReload method was stabilized as shouldRevalidate for controlling when route loaders re-run. When a shouldRevalidate function is provided, it receives a parameter with a defaultShouldRevalidate boolean value. This allows developers to opt out of specific revalidations and fall back to default behavior: function shouldRevalidate({ defaultShouldRevalidate }) { if (someEdgeCase()) return false; return defaultShouldRevalidate; }

Give your agent this brain