You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/getting-started/overview.md
+170Lines changed: 170 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -475,16 +475,175 @@ See:
475
475
476
476
## Optimistic UI
477
477
478
+
Knowing the [`formData`][formdata] being sent to an [action][action] is often enough to skip the busy indicators and render the UI in the next state immediately, even if your asynchronous work is still pending. This is called "optimistic UI".
479
+
480
+
```jsx
481
+
functionLikeButton({ tweet }) {
482
+
constfetcher=useFetcher();
483
+
484
+
// if there is `formData` then it is posting to the action
485
+
constliked=fetcher.formData
486
+
?// check the formData to be optimistic
487
+
fetcher.formData.get("liked") ==="yes"
488
+
:// if its not posting to the action, use the record's value
(Yes, HTML buttons can have a `name` and a `value`).
504
+
505
+
While it is more common to do optimistic UI with a [`fetcher`][fetcher], you can do the same with a normal form using [`navigation.formData`][navigationformdata].
506
+
478
507
## Data Fetchers
479
508
509
+
HTML Forms are the model for mutations but they have one major limitation: you can have only one at a time because a form submission is a navigation.
510
+
511
+
Most web apps need to allow for multiple mutations to be happening at the same time, like a list of records where each can be independently deleted, marked complete, liked, etc.
512
+
513
+
[Fetchers][fetcher] allow you to interact with the route [actions][action] and [loaders][loader] without causing a navigation in the browser, but still getting all the conventional benefits like error handling, revalidation, interruption handling, and race condition handling.
514
+
515
+
Imagine a list of tasks:
516
+
517
+
```jsx
518
+
functionTasks() {
519
+
consttasks=useLoaderData();
520
+
returntasks.map((task) => (
521
+
<div>
522
+
<p>{task.name}</p>
523
+
<ToggleCompleteButton task={task} />
524
+
</div>
525
+
));
526
+
}
527
+
```
528
+
529
+
Each task can be marked complete independently of the rest, with its own pending state and without causing a navigation with a [fetcher][fetcher]:
React Router will cancel stale operations and only commit fresh data automatically.
562
+
563
+
Any time you have asynchronous UI you have the risk of race conditions: when an async operation starts after but completes before an earlier operation. The result is a user interface that shows the wrong state.
564
+
565
+
Consider a search field that updates a list as the user types:
566
+
567
+
```
568
+
?q=ry |---------------|
569
+
^ commit wrong state
570
+
?q=ryan |--------|
571
+
^ lose correct state
572
+
```
573
+
574
+
Even though the query for `q?=ryan` went out later, it completed earlier. If not handled correctly, the results will briefly be the correct values for `?q=ryan` but then flip over the incorrect results for `?q=ry`. Throttling and debouncing are not enough (you can still interrupt the requests that get through). You need to cancellation.
575
+
576
+
If you're using React Router's data conventions you avoid this problem completely and automatically.
577
+
578
+
```
579
+
?q=ry |-----------X
580
+
^ cancel wrong state when
581
+
correct state completes earlier
582
+
?q=ryan |--------|
583
+
^ commit correct state
584
+
```
585
+
586
+
Not only does React Router handle race conditions for a navigation like this, it also handles it for many other cases like loading results for an autocomplete or performing multiple concurrent mutations with [`fetcher`][fetcher] (and its automatic, concurrent revalidations).
587
+
482
588
## Error Handling
483
589
590
+
The vast majority of your application errors are handled automatically by React Router. It will catch any errors that are thrown while:
591
+
592
+
- rendering
593
+
- loading data
594
+
- updating data
595
+
596
+
In practice, this is pretty much every error in your app except those thrown in event handlers (`<button onClick>`) or `useEffect`. React Router apps tend to have very few of either.
597
+
598
+
When an error is thrown, instead of rendering the route's [`element`][element], the [`errorElement`][errorelement] is rendered.
599
+
600
+
```jsx
601
+
<Route
602
+
path="/"
603
+
loader={() => {
604
+
something.that.throws.an.error();
605
+
}}
606
+
// this will not be rendered
607
+
element={<HappyPath />}
608
+
// but this will instead
609
+
errorElement={<ErrorBoundary />}
610
+
/>
611
+
```
612
+
613
+
If a route doesn't have an `errorElement`, the error will bubble to the nearest parent route with an `errorElement`:
614
+
615
+
```jsx
616
+
<Route
617
+
path="/"
618
+
element={<HappyPath />}
619
+
errorElement={<ErrorBoundary />}
620
+
>
621
+
{/* Errors here bubble up to the parent route */}
622
+
<Route path="login" element={<Login />} />
623
+
</Route>
624
+
```
625
+
626
+
See:
627
+
628
+
-[`<Route errorElement>`][errorelement]
629
+
-[`useRouteError`][userouteerror]
630
+
484
631
## Scroll Restoration
485
632
633
+
React Router will emulate the browser's scroll restoration on navigation, waiting for data to load before scrolling. This ensures the scroll position is restored to the right spot.
634
+
635
+
You can also customize the behavior by restoring based on something other than locations (like a url pathname) and preventing the scroll from happening on certain links (like tabs in the middle of a page).
636
+
637
+
See:
638
+
639
+
-[`<ScrollRestoration>`][scrollrestoration]
640
+
486
641
## Web Standard APIs
487
642
643
+
React Router is built on web standard APIs. [Loaders][loader] and [actions][action] receive standard Web Fetch API [`Request`][request] objects and can return [`Response`][response] objects, too. Cancellation is done with [Abort Signals][signal], search params are handled with [`URLSearchParams`][urlsearchparams], and data mutations are handled with [HTML Forms][htmlform].
644
+
645
+
When you get better at React Router, you get better at the web platform.
0 commit comments