Skip to content

Commit a53f483

Browse files
committed
docs: explanations work
1 parent e156dd2 commit a53f483

File tree

5 files changed

+125
-14
lines changed

5 files changed

+125
-14
lines changed

docs/explanation/code-splitting.md

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,46 @@ title: Automatic Code Splitting
44

55
# Automatic Code Splitting
66

7-
<docs-warning>
8-
This document is a work in progress. There's not much to see here (yet).
9-
</docs-warning>
7+
When using React Router's framework features, your application is automatically code split to improve the performance of initial load times when users visit your application.
8+
9+
## Code Splitting by Route
10+
11+
Consider this simple route config:
12+
13+
```tsx filename=routes.ts
14+
export default [
15+
route("/contact", "./contact.tsx"),
16+
route("/about", "./about.tsx"),
17+
];
18+
```
19+
20+
Instead of bundling all routes into a single giant build, the modules referenced (`contact.tsx` and `about.tsx`) become entry points to the bundler.
21+
22+
Because these entry points are coupled to URL segments, React Router knows just from a URL which bundles are needed in the browser, and more importantly, which are not.
23+
24+
If the user visits `"/about"` then the bundles for `about.tsx` will be loaded but not `contact.tsx`. This ensures drastically reduces the JavaScript footprint for initial page loads and speeds up your application.
25+
26+
## Removal of Server Code
27+
28+
Any server-only Route Module APIs will be removed from the bundles. Consider this route module:
29+
30+
```tsx
31+
export async function loader() {
32+
return { message: "hello" };
33+
}
34+
35+
export async function action() {
36+
console.log(Date.now());
37+
return { ok: true };
38+
}
39+
40+
export async function headers() {
41+
return { "Cache-Control": "max-age=300" };
42+
}
43+
44+
export default function Component({ loaderData }) {
45+
return <div>{loaderData.message}</div>;
46+
}
47+
```
48+
49+
After building for the browser, only the `Component` will still be in the bundle, so you can use server-only code in the other module exports.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
---
22
title: Picking a Router
3+
hidden: true
34
---
45

56
## TODO:

docs/explanation/race-conditions.md

Lines changed: 77 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,80 @@ title: Race Conditions
44

55
# Race Conditions
66

7-
<docs-warning>
8-
This document is a work in progress. There's not much to see here (yet).
9-
</docs-warning>
7+
While impossible to eliminate every possible race condition in your application, React Router automatically handles the most common race conditions found in web user interfaces.
8+
9+
## Browser Behavior
10+
11+
React Router's handling of network concurrency is heavily inspired by the behavior of web browsers when processing documents.
12+
13+
Consider clicking a link to a new document, and then clicking a different link before the new page has finished loading. The browser will:
14+
15+
1. cancel the first request
16+
2. immediately processes the new navigation
17+
18+
This behavior includes form submissions. When a pending form submission is interrupted by a new one, the first is canceled and the new submission is immediately processed.
19+
20+
## React Router Behavior
21+
22+
Like the browser, interrupted navigations with links and form submissions will cancel in flight data requests and immediately process the new event.
23+
24+
Fetchers are a bit more nuanced since they are not singleton events like navigation. Fetchers can't interrupt a other fetcher instances, but they can interrupt themselves and the behavior is the same as everything else: cancel the interrupted request and immediately process the new one.
25+
26+
Fetchers do, however, interact with each when it comes to revalidation. After a fetcher's action request returns to the browser, a revalidation for all page data is sent. This means multiple revalidation requests can be in-flight at the same time. React Router will commit all "fresh" revalidation responses and cancel any stale requests. A stale request is any request that started _earlier_ than one that has returned.
27+
28+
This management of the network prevents the most common UI bugs caused by network race conditions.
29+
30+
Since networks are unpredictable, and your server still processes these cancelled requests, your backend may still experience race conditions and have potential data integrity issues. These risks are the same risks as using default browser behavior with plain HTML `<forms>`, which we consider to be low, and outside the scope of React Router.
31+
32+
## Practical Benefits
33+
34+
Consider building a type-ahead combobox. As the user types, you send a request to the server. As they type each new character you send a new request. It's important to not show the user results for a value that's not in the text field anymore.
35+
36+
When using a fetcher, this is automatically managed for you. Consider this pseudo-code:
37+
38+
```tsx
39+
// route("/city-search", "./search-cities.ts")
40+
export async function loader({ request }) {
41+
const { searchParams } = new URL(request.url);
42+
return searchCities(searchParams.get("q"));
43+
}
44+
```
45+
46+
```tsx
47+
export function CitySearchCombobox() {
48+
const fetcher = useFetcher();
49+
50+
return (
51+
<fetcher.Form action="/city-search">
52+
<Combobox aria-label="Cities">
53+
<ComboboxInput
54+
name="q"
55+
onChange={(event) =>
56+
// submit the form onChange to get the list of cities
57+
fetcher.submit(event.target.form)
58+
}
59+
/>
60+
61+
{fetcher.data ? (
62+
<ComboboxPopover className="shadow-popup">
63+
{fetcher.data.length > 0 ? (
64+
<ComboboxList>
65+
{fetcher.data.map((city) => (
66+
<ComboboxOption
67+
key={city.id}
68+
value={city.name}
69+
/>
70+
))}
71+
</ComboboxList>
72+
) : (
73+
<span>No results found</span>
74+
)}
75+
</ComboboxPopover>
76+
) : null}
77+
</Combobox>
78+
</fetcher.Form>
79+
);
80+
}
81+
```
82+
83+
Calls to `fetcher.submit` will cancel pending requests on that fetcher automatically. This ensures you never show the user results for a request for a different input value.

docs/explanation/route-matching.md

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
---
22
title: Route Matching
3+
hidden: true
4+
# want to explain how the matching algorithm works with any potential gotchas
35
---
46

57
# Route Matching
6-
7-
<docs-warning>
8-
This document is a work in progress. There's not much to see here (yet).
9-
</docs-warning>

docs/explanation/type-safety.md

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
---
2-
title: Type safety
2+
title: Type Safety
33
---
44

5-
# Type safety
5+
# Type Safety
66

7-
<docs-info>
87
If you haven't done so already, check out our guide for <a href="../framework/how-to/setting-up-type-safety">setting up type safety</a> in a new project.
9-
</docs-info>
108

119
React Router generates types for each route in your app that you can use to get type safety for each route module export.
1210

0 commit comments

Comments
 (0)