UNPKG

6.42 kBMarkdownView Raw
1---
2title: Route Object
3order: 3
4---
5
6# Route Object
7
8[MODES: data]
9
10## Introduction
11
12The objects passed to `createBrowserRouter` are called Route Objects.
13
14```tsx lines=[2-5]
15createBrowserRouter([
16 {
17 path: "/",
18 Component: App,
19 },
20]);
21```
22
23Route modules are the foundation of React Router's data features, they define:
24
25- data loading
26- actions
27- revalidation
28- error boundaries
29- and more
30
31This guide is a quick overview of every route object feature.
32
33## Component
34
35The `Component` property in a route object defines the component that will render when the route matches.
36
37```tsx lines=[4]
38createBrowserRouter([
39 {
40 path: "/",
41 Component: MyRouteComponent,
42 },
43]);
44
45function MyRouteComponent() {
46 return (
47 <div>
48 <h1>Look ma!</h1>
49 <p>
50 I'm still using React Router after like 10 years.
51 </p>
52 </div>
53 );
54}
55```
56
57## `middleware`
58
59Route [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.
60
61```tsx
62createBrowserRouter([
63 {
64 path: "/",
65 middleware: [loggingMiddleware],
66 loader: rootLoader,
67 Component: Root,
68 children: [{
69 path: 'auth',
70 middleware: [authMiddleware],
71 loader: authLoader,
72 Component: Auth,
73 children: [...]
74 }]
75 },
76]);
77
78async function loggingMiddleware({ request }, next) {
79 let url = new URL(request.url);
80 console.log(`Starting navigation: ${url.pathname}${url.search}`);
81 const start = performance.now();
82 await next();
83 const duration = performance.now() - start;
84 console.log(`Navigation completed in ${duration}ms`);
85}
86
87const userContext = createContext<User>();
88
89async function authMiddleware ({ context }) {
90 const userId = getUserId();
91
92 if (!userId) {
93 throw redirect("/login");
94 }
95
96 context.set(userContext, await getUserById(userId));
97};
98```
99
100See also:
101
102- [Middleware][middleware]
103
104## `loader`
105
106Route loaders provide data to route components before they are rendered.
107
108```tsx
109import {
110 useLoaderData,
111 createBrowserRouter,
112} from "react-router";
113
114createBrowserRouter([
115 {
116 path: "/",
117 loader: loader,
118 Component: MyRoute,
119 },
120]);
121
122async function loader({ params }) {
123 return { message: "Hello, world!" };
124}
125
126function MyRoute() {
127 let data = useLoaderData();
128 return <h1>{data.message}</h1>;
129}
130```
131
132See also:
133
134- [`loader` params][loader-params]
135
136## `action`
137
138Route actions allow server-side data mutations with automatic revalidation of all loader data on the page when called from `<Form>`, `useFetcher`, and `useSubmit`.
139
140```tsx
141import {
142 createBrowserRouter,
143 useLoaderData,
144 useActionData,
145 Form,
146} from "react-router";
147import { TodoList } from "~/components/TodoList";
148
149createBrowserRouter([
150 {
151 path: "/items",
152 action: action,
153 loader: loader,
154 Component: Items,
155 },
156]);
157
158async function action({ request }) {
159 const data = await request.formData();
160 const todo = await fakeDb.addItem({
161 title: data.get("title"),
162 });
163 return { ok: true };
164}
165
166// this data will be revalidated after the action completes...
167async function loader() {
168 const items = await fakeDb.getItems();
169 return { items };
170}
171
172// ...so that the list here is updated automatically
173export default function Items() {
174 let data = useLoaderData();
175 return (
176 <div>
177 <List items={data.items} />
178 <Form method="post" navigate={false}>
179 <input type="text" name="title" />
180 <button type="submit">Create Todo</button>
181 </Form>
182 </div>
183 );
184}
185```
186
187## `shouldRevalidate`
188
189Loader data is automatically revalidated after certain events like navigations and form submissions.
190
191This 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.
192
193A route loader is revalidated when:
194
195- its own route params change
196- any change to URL search params
197- after an action is called and returns a non-error status code
198
199By 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.
200
201```tsx
202import type { ShouldRevalidateFunctionArgs } from "react-router";
203
204function shouldRevalidate({
205 formMethod,
206 formAction,
207 defaultShouldRevalidate,
208}: ShouldRevalidateFunctionArgs) {
209 if (
210 formMethod === "POST" &&
211 formAction?.endsWith("/analytics")
212 ) {
213 return false;
214 }
215
216 return defaultShouldRevalidate;
217}
218
219createBrowserRouter([
220 {
221 path: "/",
222 shouldRevalidate,
223 Component: MyRoute,
224 },
225]);
226```
227
228To 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.
229
230See [Revalidation Optimization][optimize-revalidation] for call-site opt-out, parent/child behavior, and more examples.
231
232[`ShouldRevalidateFunctionArgs` Reference Documentation ↗](https://api.reactrouter.com/v8/interfaces/react-router.ShouldRevalidateFunctionArgs.html)
233
234Please note the default behavior is different in [Framework Mode](../modes).
235
236## `lazy`
237
238Most properties can be lazily imported to reduce the initial bundle size.
239
240```tsx
241createBrowserRouter([
242 {
243 path: "/app",
244 lazy: async () => {
245 // load component and loader in parallel before rendering
246 const [Component, loader] = await Promise.all([
247 import("./app"),
248 import("./app-loader"),
249 ]);
250 return { Component, loader };
251 },
252 },
253]);
254```
255
256## `handle`
257
258Route handle allows apps to add anything to a route match in `useMatches` to create abstractions (like breadcrumbs, etc.).
259
260```tsx
261createBrowserRouter([
262 {
263 path: "/app",
264 handle: {
265 breadcrumb: "App",
266 },
267 },
268]);
269```
270
271See also:
272
273- [`useMatches`][use-matches]
274
275---
276
277Next: [Data Loading](./data-loading)
278
279[form-default-should-revalidate]: ../../api/components/Form#defaultshouldrevalidate
280[loader-params]: https://api.reactrouter.com/v8/interfaces/react-router.LoaderFunctionArgs
281[middleware]: ../../how-to/middleware
282[optimize-revalidation]: ../../how-to/optimize-revalidation
283[use-matches]: ../../api/hooks/useMatches