react-router
Version:
Declarative routing for React
284 lines (221 loc) • 6.42 kB
Markdown
---
title: Route Object
order: 3
---
# Route Object
[MODES: data]
## Introduction
The objects passed to `createBrowserRouter` are called Route Objects.
```tsx lines=[2-5]
createBrowserRouter([
{
path: "/",
Component: App,
},
]);
```
Route modules are the foundation of React Router's data features, they define:
- data loading
- actions
- revalidation
- error boundaries
- and more
This guide is a quick overview of every route object feature.
## Component
The `Component` property in a route object defines the component that will render when the route matches.
```tsx lines=[4]
createBrowserRouter([
{
path: "/",
Component: MyRouteComponent,
},
]);
function MyRouteComponent() {
return (
<div>
<h1>Look ma!</h1>
<p>
I'm still using React Router after like 10 years.
</p>
</div>
);
}
```
## `middleware`
Route [middleware][middleware] runs sequentially before and after navigations. This gives you a singular place to do things like logging and authentication. The `next` function continues down the chain, and on the leaf route the `next` function executes the loaders/actions for the navigation.
```tsx
createBrowserRouter([
{
path: "/",
middleware: [loggingMiddleware],
loader: rootLoader,
Component: Root,
children: [{
path: 'auth',
middleware: [authMiddleware],
loader: authLoader,
Component: Auth,
children: [...]
}]
},
]);
async function loggingMiddleware({ request }, next) {
let url = new URL(request.url);
console.log(`Starting navigation: ${url.pathname}${url.search}`);
const start = performance.now();
await next();
const duration = performance.now() - start;
console.log(`Navigation completed in ${duration}ms`);
}
const userContext = createContext<User>();
async function authMiddleware ({ context }) {
const userId = getUserId();
if (!userId) {
throw redirect("/login");
}
context.set(userContext, await getUserById(userId));
};
```
See also:
- [Middleware][middleware]
## `loader`
Route loaders provide data to route components before they are rendered.
```tsx
import {
useLoaderData,
createBrowserRouter,
} from "react-router";
createBrowserRouter([
{
path: "/",
loader: loader,
Component: MyRoute,
},
]);
async function loader({ params }) {
return { message: "Hello, world!" };
}
function MyRoute() {
let data = useLoaderData();
return <h1>{data.message}</h1>;
}
```
See also:
- [`loader` params][loader-params]
## `action`
Route actions allow server-side data mutations with automatic revalidation of all loader data on the page when called from `<Form>`, `useFetcher`, and `useSubmit`.
```tsx
import {
createBrowserRouter,
useLoaderData,
useActionData,
Form,
} from "react-router";
import { TodoList } from "~/components/TodoList";
createBrowserRouter([
{
path: "/items",
action: action,
loader: loader,
Component: Items,
},
]);
async function action({ request }) {
const data = await request.formData();
const todo = await fakeDb.addItem({
title: data.get("title"),
});
return { ok: true };
}
// this data will be revalidated after the action completes...
async function loader() {
const items = await fakeDb.getItems();
return { items };
}
// ...so that the list here is updated automatically
export default function Items() {
let data = useLoaderData();
return (
<div>
<List items={data.items} />
<Form method="post" navigate={false}>
<input type="text" name="title" />
<button type="submit">Create Todo</button>
</Form>
</div>
);
}
```
## `shouldRevalidate`
Loader data is automatically revalidated after certain events like navigations and form submissions.
This function lets you opt in or out of the default revalidation behavior **for this route's loader**. It does not skip parent or sibling loaders. The default behavior is nuanced to avoid calling loaders unnecessarily.
A route loader is revalidated when:
- its own route params change
- any change to URL search params
- after an action is called and returns a non-error status code
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.
```tsx
import type { ShouldRevalidateFunctionArgs } from "react-router";
function shouldRevalidate({
formMethod,
formAction,
defaultShouldRevalidate,
}: ShouldRevalidateFunctionArgs) {
if (
formMethod === "POST" &&
formAction?.endsWith("/analytics")
) {
return false;
}
return defaultShouldRevalidate;
}
createBrowserRouter([
{
path: "/",
shouldRevalidate,
Component: MyRoute,
},
]);
```
To skip revalidation for a single `<Form>`, `<Link>`, `useSubmit`, or `fetcher.submit`, pass [`defaultShouldRevalidate={false}`][form-default-should-revalidate] at the call site. Routes without `shouldRevalidate` use that value directly.
See [Revalidation Optimization][optimize-revalidation] for call-site opt-out, parent/child behavior, and more examples.
[`ShouldRevalidateFunctionArgs` Reference Documentation ↗](https://api.reactrouter.com/v8/interfaces/react-router.ShouldRevalidateFunctionArgs.html)
Please note the default behavior is different in [Framework Mode](../modes).
## `lazy`
Most properties can be lazily imported to reduce the initial bundle size.
```tsx
createBrowserRouter([
{
path: "/app",
lazy: async () => {
// load component and loader in parallel before rendering
const [Component, loader] = await Promise.all([
import("./app"),
import("./app-loader"),
]);
return { Component, loader };
},
},
]);
```
## `handle`
Route handle allows apps to add anything to a route match in `useMatches` to create abstractions (like breadcrumbs, etc.).
```tsx
createBrowserRouter([
{
path: "/app",
handle: {
breadcrumb: "App",
},
},
]);
```
See also:
- [`useMatches`][use-matches]
---
Next: [Data Loading](./data-loading)
[form-default-should-revalidate]: ../../api/components/Form#defaultshouldrevalidate
[loader-params]: https://api.reactrouter.com/v8/interfaces/react-router.LoaderFunctionArgs
[middleware]: ../../how-to/middleware
[optimize-revalidation]: ../../how-to/optimize-revalidation
[use-matches]: ../../api/hooks/useMatches