react-router 7.15.1 → 7.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +27 -2
- package/dist/development/{browser-3AnU12UI.d.mts → browser-CGcs-0pD.d.mts} +2 -2
- package/dist/development/{browser-BOdXz9dK.d.ts → browser-D3uq9sI1.d.ts} +2 -2
- package/dist/development/{chunk-4N6VE7H7.mjs → chunk-6CSD65Y2.mjs} +12 -11
- package/dist/development/{chunk-RJYABSBD.mjs → chunk-ASILSGTR.mjs} +6 -6
- package/dist/development/{chunk-D6LUOGOQ.js → chunk-KFNXW4AL.js} +10 -10
- package/dist/{production/chunk-Y6IFXO7V.js → development/chunk-PBLBZ3QU.js} +7 -7
- package/dist/development/{chunk-66UKHEGQ.js → chunk-PULC7NLK.js} +100 -99
- package/dist/{production/context-ByvtofY2.d.mts → development/context-CmHpk1Ws.d.mts} +3 -3
- package/dist/development/{data-BqZ2x964.d.ts → data-D4xhSy90.d.ts} +1 -1
- package/dist/{production/data-BVUf681J.d.mts → development/data-U8FS-wNn.d.mts} +1 -1
- package/dist/development/dom-export.d.mts +4 -4
- package/dist/development/dom-export.d.ts +4 -4
- package/dist/development/dom-export.js +30 -30
- package/dist/development/dom-export.mjs +5 -5
- package/dist/{production/index-react-server-client-BS5F89FR.d.ts → development/index-react-server-client-CwU9bE5R.d.ts} +4 -4
- package/dist/{production/index-react-server-client-DY04-103.d.mts → development/index-react-server-client-DPrDrCew.d.mts} +3 -3
- package/dist/development/index-react-server-client.d.mts +3 -3
- package/dist/development/index-react-server-client.d.ts +3 -3
- package/dist/development/index-react-server-client.js +4 -4
- package/dist/development/index-react-server-client.mjs +2 -2
- package/dist/development/index-react-server.d.mts +1 -1
- package/dist/development/index-react-server.d.ts +1 -1
- package/dist/development/index-react-server.js +1 -1
- package/dist/development/index-react-server.mjs +1 -1
- package/dist/development/index.d.mts +18 -12
- package/dist/development/index.d.ts +18 -12
- package/dist/development/index.js +89 -89
- package/dist/development/index.mjs +3 -3
- package/dist/{production/instrumentation-cRWWLfsU.d.ts → development/instrumentation-1q4YhLGP.d.ts} +2 -2
- package/dist/development/lib/types/internal.d.mts +2 -2
- package/dist/development/lib/types/internal.d.ts +2 -2
- package/dist/development/lib/types/internal.js +1 -1
- package/dist/development/lib/types/internal.mjs +1 -1
- package/dist/development/{register-Bsscfj79.d.ts → register-CNAx3TXj.d.ts} +1 -1
- package/dist/development/{register-Df8okEea.d.mts → register-CqK96Zfk.d.mts} +1 -1
- package/dist/production/{browser-3AnU12UI.d.mts → browser-CGcs-0pD.d.mts} +2 -2
- package/dist/production/{browser-BOdXz9dK.d.ts → browser-D3uq9sI1.d.ts} +2 -2
- package/dist/production/{chunk-6S4627ZB.mjs → chunk-5TQZEVD5.mjs} +6 -6
- package/dist/{development/chunk-4YRVXM2U.js → production/chunk-CTIXC7EV.js} +7 -7
- package/dist/production/{chunk-PNZCCTKT.js → chunk-EN242BO4.js} +100 -99
- package/dist/production/{chunk-JAKZPQZC.mjs → chunk-OSYEOCBT.mjs} +12 -11
- package/dist/production/{chunk-HUBUW7R3.js → chunk-RTRY3JFT.js} +10 -10
- package/dist/{development/context-ByvtofY2.d.mts → production/context-CmHpk1Ws.d.mts} +3 -3
- package/dist/production/{data-BqZ2x964.d.ts → data-D4xhSy90.d.ts} +1 -1
- package/dist/{development/data-BVUf681J.d.mts → production/data-U8FS-wNn.d.mts} +1 -1
- package/dist/production/dom-export.d.mts +4 -4
- package/dist/production/dom-export.d.ts +4 -4
- package/dist/production/dom-export.js +30 -30
- package/dist/production/dom-export.mjs +5 -5
- package/dist/{development/index-react-server-client-BS5F89FR.d.ts → production/index-react-server-client-CwU9bE5R.d.ts} +4 -4
- package/dist/{development/index-react-server-client-DY04-103.d.mts → production/index-react-server-client-DPrDrCew.d.mts} +3 -3
- package/dist/production/index-react-server-client.d.mts +3 -3
- package/dist/production/index-react-server-client.d.ts +3 -3
- package/dist/production/index-react-server-client.js +4 -4
- package/dist/production/index-react-server-client.mjs +2 -2
- package/dist/production/index-react-server.d.mts +1 -1
- package/dist/production/index-react-server.d.ts +1 -1
- package/dist/production/index-react-server.js +1 -1
- package/dist/production/index-react-server.mjs +1 -1
- package/dist/production/index.d.mts +18 -12
- package/dist/production/index.d.ts +18 -12
- package/dist/production/index.js +89 -89
- package/dist/production/index.mjs +3 -3
- package/dist/{development/instrumentation-cRWWLfsU.d.ts → production/instrumentation-1q4YhLGP.d.ts} +2 -2
- package/dist/production/lib/types/internal.d.mts +2 -2
- package/dist/production/lib/types/internal.d.ts +2 -2
- package/dist/production/lib/types/internal.js +1 -1
- package/dist/production/lib/types/internal.mjs +1 -1
- package/dist/production/{register-Bsscfj79.d.ts → register-CNAx3TXj.d.ts} +1 -1
- package/dist/production/{register-Df8okEea.d.mts → register-CqK96Zfk.d.mts} +1 -1
- package/docs/explanation/backend-for-frontend.md +50 -0
- package/docs/explanation/code-splitting.md +61 -0
- package/docs/explanation/concurrency.md +135 -0
- package/docs/explanation/form-vs-fetcher.md +292 -0
- package/docs/explanation/hot-module-replacement.md +137 -0
- package/docs/explanation/hydration.md +14 -0
- package/docs/explanation/index-query-param.md +86 -0
- package/docs/explanation/index.md +4 -0
- package/docs/explanation/lazy-route-discovery.md +78 -0
- package/docs/explanation/location.md +6 -0
- package/docs/explanation/progressive-enhancement.md +150 -0
- package/docs/explanation/race-conditions.md +88 -0
- package/docs/explanation/react-transitions.md +160 -0
- package/docs/explanation/route-matching.md +7 -0
- package/docs/explanation/server-client-execution.md +4 -0
- package/docs/explanation/sessions-and-cookies.md +465 -0
- package/docs/explanation/special-files.md +16 -0
- package/docs/explanation/state-management.md +524 -0
- package/docs/explanation/styling.md +87 -0
- package/docs/explanation/type-safety.md +82 -0
- package/docs/how-to/accessibility.md +44 -0
- package/docs/how-to/client-data.md +199 -0
- package/docs/how-to/data-strategy.md +317 -0
- package/docs/how-to/error-boundary.md +231 -0
- package/docs/how-to/error-reporting.md +142 -0
- package/docs/how-to/fetchers.md +307 -0
- package/docs/how-to/file-route-conventions.md +410 -0
- package/docs/how-to/file-uploads.md +217 -0
- package/docs/how-to/form-validation.md +120 -0
- package/docs/how-to/headers.md +164 -0
- package/docs/how-to/index.md +4 -0
- package/docs/how-to/instrumentation.md +556 -0
- package/docs/how-to/meta.md +40 -0
- package/docs/how-to/middleware.md +763 -0
- package/docs/how-to/navigation-blocking.md +233 -0
- package/docs/how-to/optimize-revalidation.md +12 -0
- package/docs/how-to/pre-rendering.md +225 -0
- package/docs/how-to/presets.md +103 -0
- package/docs/how-to/react-server-components.md +899 -0
- package/docs/how-to/resource-routes.md +126 -0
- package/docs/how-to/route-module-type-safety.md +100 -0
- package/docs/how-to/search-params.md +4 -0
- package/docs/how-to/security.md +30 -0
- package/docs/how-to/server-bundles.md +66 -0
- package/docs/how-to/spa.md +120 -0
- package/docs/how-to/status.md +63 -0
- package/docs/how-to/suspense.md +132 -0
- package/docs/how-to/using-handle.md +117 -0
- package/docs/how-to/view-transitions.md +237 -0
- package/docs/how-to/webhook.md +50 -0
- package/docs/index.md +39 -0
- package/docs/start/data/actions.md +138 -0
- package/docs/start/data/custom.md +198 -0
- package/docs/start/data/data-loading.md +44 -0
- package/docs/start/data/index.md +4 -0
- package/docs/start/data/installation.md +52 -0
- package/docs/start/data/navigating.md +12 -0
- package/docs/start/data/pending-ui.md +12 -0
- package/docs/start/data/route-object.md +268 -0
- package/docs/start/data/routing.md +281 -0
- package/docs/start/data/testing.md +8 -0
- package/docs/start/declarative/index.md +4 -0
- package/docs/start/declarative/installation.md +43 -0
- package/docs/start/declarative/navigating.md +133 -0
- package/docs/start/declarative/routing.md +237 -0
- package/docs/start/declarative/url-values.md +65 -0
- package/docs/start/framework/actions.md +174 -0
- package/docs/start/framework/data-loading.md +201 -0
- package/docs/start/framework/deploying.md +96 -0
- package/docs/start/framework/index.md +4 -0
- package/docs/start/framework/installation.md +41 -0
- package/docs/start/framework/navigating.md +182 -0
- package/docs/start/framework/pending-ui.md +142 -0
- package/docs/start/framework/rendering.md +59 -0
- package/docs/start/framework/route-module.md +527 -0
- package/docs/start/framework/routing.md +362 -0
- package/docs/start/framework/testing.md +133 -0
- package/docs/start/index.md +4 -0
- package/docs/start/modes.md +201 -0
- package/docs/upgrading/component-routes.md +363 -0
- package/docs/upgrading/future.md +280 -0
- package/docs/upgrading/index.md +4 -0
- package/docs/upgrading/remix.md +403 -0
- package/docs/upgrading/router-provider.md +442 -0
- package/docs/upgrading/v6.md +382 -0
- package/package.json +2 -1
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Navigating
|
|
3
|
+
order: 6
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Navigating
|
|
7
|
+
|
|
8
|
+
[MODES: framework]
|
|
9
|
+
|
|
10
|
+
## Introduction
|
|
11
|
+
|
|
12
|
+
Users navigate your application with `<Link>`, `<NavLink>`, `<Form>`, `redirect`, and `useNavigate`.
|
|
13
|
+
|
|
14
|
+
## NavLink
|
|
15
|
+
|
|
16
|
+
This component is for navigation links that need to render active and pending states.
|
|
17
|
+
|
|
18
|
+
```tsx
|
|
19
|
+
import { NavLink } from "react-router";
|
|
20
|
+
|
|
21
|
+
export function MyAppNav() {
|
|
22
|
+
return (
|
|
23
|
+
<nav>
|
|
24
|
+
<NavLink to="/" end>
|
|
25
|
+
Home
|
|
26
|
+
</NavLink>
|
|
27
|
+
<NavLink to="/trending" end>
|
|
28
|
+
Trending Concerts
|
|
29
|
+
</NavLink>
|
|
30
|
+
<NavLink to="/concerts">All Concerts</NavLink>
|
|
31
|
+
<NavLink to="/account">Account</NavLink>
|
|
32
|
+
</nav>
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
`NavLink` renders default class names for different states for easy styling with CSS:
|
|
38
|
+
|
|
39
|
+
```css
|
|
40
|
+
a.active {
|
|
41
|
+
color: red;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
a.pending {
|
|
45
|
+
animate: pulse 1s infinite;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
a.transitioning {
|
|
49
|
+
/* css transition is running */
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
It also has callback props on `className`, `style`, and `children` with the states for inline styling or conditional rendering:
|
|
54
|
+
|
|
55
|
+
```tsx
|
|
56
|
+
// className
|
|
57
|
+
<NavLink
|
|
58
|
+
to="/messages"
|
|
59
|
+
className={({ isActive, isPending, isTransitioning }) =>
|
|
60
|
+
[
|
|
61
|
+
isPending ? "pending" : "",
|
|
62
|
+
isActive ? "active" : "",
|
|
63
|
+
isTransitioning ? "transitioning" : "",
|
|
64
|
+
].join(" ")
|
|
65
|
+
}
|
|
66
|
+
>
|
|
67
|
+
Messages
|
|
68
|
+
</NavLink>
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
```tsx
|
|
72
|
+
// style
|
|
73
|
+
<NavLink
|
|
74
|
+
to="/messages"
|
|
75
|
+
style={({ isActive, isPending, isTransitioning }) => {
|
|
76
|
+
return {
|
|
77
|
+
fontWeight: isActive ? "bold" : "",
|
|
78
|
+
color: isPending ? "red" : "black",
|
|
79
|
+
viewTransitionName: isTransitioning ? "slide" : "",
|
|
80
|
+
};
|
|
81
|
+
}}
|
|
82
|
+
>
|
|
83
|
+
Messages
|
|
84
|
+
</NavLink>
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
```tsx
|
|
88
|
+
// children
|
|
89
|
+
<NavLink to="/tasks">
|
|
90
|
+
{({ isActive, isPending, isTransitioning }) => (
|
|
91
|
+
<span className={isActive ? "active" : ""}>Tasks</span>
|
|
92
|
+
)}
|
|
93
|
+
</NavLink>
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Link
|
|
97
|
+
|
|
98
|
+
Use `<Link>` when the link doesn't need active styling:
|
|
99
|
+
|
|
100
|
+
```tsx
|
|
101
|
+
import { Link } from "react-router";
|
|
102
|
+
|
|
103
|
+
export function LoggedOutMessage() {
|
|
104
|
+
return (
|
|
105
|
+
<p>
|
|
106
|
+
You've been logged out.{" "}
|
|
107
|
+
<Link to="/login">Login again</Link>
|
|
108
|
+
</p>
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Form
|
|
114
|
+
|
|
115
|
+
The form component can be used to navigate with `URLSearchParams` provided by the user.
|
|
116
|
+
|
|
117
|
+
```tsx
|
|
118
|
+
<Form action="/search">
|
|
119
|
+
<input type="text" name="q" />
|
|
120
|
+
</Form>
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
If the user enters "journey" into the input and submits it, they will navigate to:
|
|
124
|
+
|
|
125
|
+
```
|
|
126
|
+
/search?q=journey
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Forms with `<Form method="post" />` will also navigate to the action prop but will submit the data as `FormData` instead of `URLSearchParams`. However, it is more common to `useFetcher()` to POST form data. See [Using Fetchers](../../how-to/fetchers).
|
|
130
|
+
|
|
131
|
+
## redirect
|
|
132
|
+
|
|
133
|
+
Inside of route loaders and actions, you can return a `redirect` to another URL.
|
|
134
|
+
|
|
135
|
+
```tsx
|
|
136
|
+
import { redirect } from "react-router";
|
|
137
|
+
|
|
138
|
+
export async function loader({ request }) {
|
|
139
|
+
let user = await getUser(request);
|
|
140
|
+
if (!user) {
|
|
141
|
+
return redirect("/login");
|
|
142
|
+
}
|
|
143
|
+
return { userName: user.name };
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
It is common to redirect to a new record after it has been created:
|
|
148
|
+
|
|
149
|
+
```tsx
|
|
150
|
+
import { redirect } from "react-router";
|
|
151
|
+
|
|
152
|
+
export async function action({ request }) {
|
|
153
|
+
let formData = await request.formData();
|
|
154
|
+
let project = await createProject(formData);
|
|
155
|
+
return redirect(`/projects/${project.id}`);
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## useNavigate
|
|
160
|
+
|
|
161
|
+
This hook allows the programmer to navigate the user to a new page without the user interacting. Usage of this hook should be uncommon. It's recommended to use the other APIs in this guide when possible.
|
|
162
|
+
|
|
163
|
+
Reserve usage of `useNavigate` to situations where the user is _not_ interacting but you need to navigate, for example:
|
|
164
|
+
|
|
165
|
+
- Logging them out after inactivity
|
|
166
|
+
- Timed UIs like quizzes, etc.
|
|
167
|
+
|
|
168
|
+
```tsx
|
|
169
|
+
import { useNavigate } from "react-router";
|
|
170
|
+
|
|
171
|
+
export function useLogoutAfterInactivity() {
|
|
172
|
+
let navigate = useNavigate();
|
|
173
|
+
|
|
174
|
+
useFakeInactivityHook(() => {
|
|
175
|
+
navigate("/logout");
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
Next: [Pending UI](./pending-ui)
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Pending UI
|
|
3
|
+
order: 7
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Pending UI
|
|
7
|
+
|
|
8
|
+
[MODES: framework]
|
|
9
|
+
|
|
10
|
+
## Introduction
|
|
11
|
+
|
|
12
|
+
When the user navigates to a new route, or submits data to an action, the UI should immediately respond to the user's actions with a pending or optimistic state. Application code is responsible for this.
|
|
13
|
+
|
|
14
|
+
## Global Pending Navigation
|
|
15
|
+
|
|
16
|
+
When the user navigates to a new url, the loaders for the next page are awaited before the next page renders. You can get the pending state from `useNavigation`.
|
|
17
|
+
|
|
18
|
+
```tsx
|
|
19
|
+
import { useNavigation } from "react-router";
|
|
20
|
+
|
|
21
|
+
export default function Root() {
|
|
22
|
+
const navigation = useNavigation();
|
|
23
|
+
const isNavigating = Boolean(navigation.location);
|
|
24
|
+
|
|
25
|
+
return (
|
|
26
|
+
<html>
|
|
27
|
+
<body>
|
|
28
|
+
{isNavigating && <GlobalSpinner />}
|
|
29
|
+
<Outlet />
|
|
30
|
+
</body>
|
|
31
|
+
</html>
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Local Pending Navigation
|
|
37
|
+
|
|
38
|
+
Pending indicators can also be localized to the link. NavLink's children, className, and style props can be functions that receive the pending state.
|
|
39
|
+
|
|
40
|
+
```tsx
|
|
41
|
+
import { NavLink } from "react-router";
|
|
42
|
+
|
|
43
|
+
function Navbar() {
|
|
44
|
+
return (
|
|
45
|
+
<nav>
|
|
46
|
+
<NavLink to="/home">
|
|
47
|
+
{({ isPending }) => (
|
|
48
|
+
<span>Home {isPending && <Spinner />}</span>
|
|
49
|
+
)}
|
|
50
|
+
</NavLink>
|
|
51
|
+
<NavLink
|
|
52
|
+
to="/about"
|
|
53
|
+
style={({ isPending }) => ({
|
|
54
|
+
color: isPending ? "gray" : "black",
|
|
55
|
+
})}
|
|
56
|
+
>
|
|
57
|
+
About
|
|
58
|
+
</NavLink>
|
|
59
|
+
</nav>
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Pending Form Submission
|
|
65
|
+
|
|
66
|
+
When a form is submitted, the UI should immediately respond to the user's actions with a pending state. This is easiest to do with a [fetcher][use_fetcher] form because it has its own independent state (whereas normal forms cause a global navigation).
|
|
67
|
+
|
|
68
|
+
```tsx filename=app/project.tsx lines=[10-12]
|
|
69
|
+
import { useFetcher } from "react-router";
|
|
70
|
+
|
|
71
|
+
function NewProjectForm() {
|
|
72
|
+
const fetcher = useFetcher();
|
|
73
|
+
|
|
74
|
+
return (
|
|
75
|
+
<fetcher.Form method="post">
|
|
76
|
+
<input type="text" name="title" />
|
|
77
|
+
<button type="submit">
|
|
78
|
+
{fetcher.state !== "idle"
|
|
79
|
+
? "Submitting..."
|
|
80
|
+
: "Submit"}
|
|
81
|
+
</button>
|
|
82
|
+
</fetcher.Form>
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
For non-fetcher form submissions, pending states are available on `useNavigation`.
|
|
88
|
+
|
|
89
|
+
```tsx filename=app/projects/new.tsx
|
|
90
|
+
import { useNavigation, Form } from "react-router";
|
|
91
|
+
|
|
92
|
+
function NewProjectForm() {
|
|
93
|
+
const navigation = useNavigation();
|
|
94
|
+
|
|
95
|
+
return (
|
|
96
|
+
<Form method="post" action="/projects/new">
|
|
97
|
+
<input type="text" name="title" />
|
|
98
|
+
<button type="submit">
|
|
99
|
+
{navigation.formAction === "/projects/new"
|
|
100
|
+
? "Submitting..."
|
|
101
|
+
: "Submit"}
|
|
102
|
+
</button>
|
|
103
|
+
</Form>
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Optimistic UI
|
|
109
|
+
|
|
110
|
+
When the future state of the UI is known by the form submission data, an optimistic UI can be implemented for instant UX.
|
|
111
|
+
|
|
112
|
+
```tsx filename=app/project.tsx lines=[4-7]
|
|
113
|
+
function Task({ task }) {
|
|
114
|
+
const fetcher = useFetcher();
|
|
115
|
+
|
|
116
|
+
let isComplete = task.status === "complete";
|
|
117
|
+
if (fetcher.formData) {
|
|
118
|
+
isComplete =
|
|
119
|
+
fetcher.formData.get("status") === "complete";
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return (
|
|
123
|
+
<div>
|
|
124
|
+
<div>{task.title}</div>
|
|
125
|
+
<fetcher.Form method="post">
|
|
126
|
+
<button
|
|
127
|
+
name="status"
|
|
128
|
+
value={isComplete ? "incomplete" : "complete"}
|
|
129
|
+
>
|
|
130
|
+
{isComplete ? "Mark Incomplete" : "Mark Complete"}
|
|
131
|
+
</button>
|
|
132
|
+
</fetcher.Form>
|
|
133
|
+
</div>
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
Next: [Testing](./testing)
|
|
141
|
+
|
|
142
|
+
[use_fetcher]: https://api.reactrouter.com/v7/functions/react-router.useFetcher.html
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Rendering Strategies
|
|
3
|
+
order: 4
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Rendering Strategies
|
|
7
|
+
|
|
8
|
+
[MODES: framework]
|
|
9
|
+
|
|
10
|
+
## Introduction
|
|
11
|
+
|
|
12
|
+
There are three rendering strategies in React Router:
|
|
13
|
+
|
|
14
|
+
- Client Side Rendering
|
|
15
|
+
- Server Side Rendering
|
|
16
|
+
- Static Pre-rendering
|
|
17
|
+
|
|
18
|
+
## Client Side Rendering
|
|
19
|
+
|
|
20
|
+
Routes are always client side rendered as the user navigates around the app. If you're looking to build a Single Page App, disable server rendering:
|
|
21
|
+
|
|
22
|
+
```ts filename=react-router.config.ts
|
|
23
|
+
import type { Config } from "@react-router/dev/config";
|
|
24
|
+
|
|
25
|
+
export default {
|
|
26
|
+
ssr: false,
|
|
27
|
+
} satisfies Config;
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Server Side Rendering
|
|
31
|
+
|
|
32
|
+
```ts filename=react-router.config.ts
|
|
33
|
+
import type { Config } from "@react-router/dev/config";
|
|
34
|
+
|
|
35
|
+
export default {
|
|
36
|
+
ssr: true,
|
|
37
|
+
} satisfies Config;
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Server side rendering requires a deployment that supports it. Though it's a global setting, individual routes can still be statically pre-rendered. Routes can also use client data loading with `clientLoader` to avoid server rendering/fetching for their portion of the UI.
|
|
41
|
+
|
|
42
|
+
## Static Pre-rendering
|
|
43
|
+
|
|
44
|
+
```ts filename=react-router.config.ts
|
|
45
|
+
import type { Config } from "@react-router/dev/config";
|
|
46
|
+
|
|
47
|
+
export default {
|
|
48
|
+
// return a list of URLs to prerender at build time
|
|
49
|
+
async prerender() {
|
|
50
|
+
return ["/", "/about", "/contact"];
|
|
51
|
+
},
|
|
52
|
+
} satisfies Config;
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Pre-rendering is a build-time operation that generates static HTML and client navigation data payloads for a list of URLs. This is useful for SEO and performance, especially for deployments without server rendering. When pre-rendering, route module loaders are used to fetch data at build time.
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
Next: [Data Loading](./data-loading)
|