UNPKG

5.7 kB Markdown View 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 hook enables you to opt in or out of the default revalidation behavior. 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 arg: ShouldRevalidateFunctionArgs,
206) {
207 return true; // false
208}
209
210createBrowserRouter([
211 {
212 path: "/",
213 shouldRevalidate: shouldRevalidate,
214 Component: MyRoute,
215 },
216]);
217```
218
219[`ShouldRevalidateFunctionArgs` Reference Documentation ↗](https://api.reactrouter.com/v7/interfaces/react-router.ShouldRevalidateFunctionArgs.html)
220
221Please note the default behavior is different in [Framework Mode](../modes).
222
223## `lazy`
224
225Most properties can be lazily imported to reduce the initial bundle size.
226
227```tsx
228createBrowserRouter([
229 {
230 path: "/app",
231 lazy: async () => {
232 // load component and loader in parallel before rendering
233 const [Component, loader] = await Promise.all([
234 import("./app"),
235 import("./app-loader"),
236 ]);
237 return { Component, loader };
238 },
239 },
240]);
241```
242
243## `handle`
244
245Route handle allows apps to add anything to a route match in `useMatches` to create abstractions (like breadcrumbs, etc.).
246
247```tsx
248createBrowserRouter([
249 {
250 path: "/app",
251 handle: {
252 breadcrumb: "App",
253 },
254 },
255]);
256```
257
258See also:
259
260- [`useMatches`][use-matches]
261
262---
263
264Next: [Data Loading](./data-loading)
265
266[loader-params]: https://api.reactrouter.com/v7/interfaces/react-router.LoaderFunctionArgs
267[middleware]: ../../how-to/middleware
268[use-matches]: ../../api/hooks/useMatches