Skip to content

Commit

Permalink
docs(tutorial): add loading="lazy" to images
Browse files Browse the repository at this point in the history
  • Loading branch information
brookslybrand committed Dec 17, 2024
1 parent 7dd50ad commit 33165a2
Showing 1 changed file with 20 additions and 20 deletions.
40 changes: 20 additions & 20 deletions docs/tutorials/address-book.md
Original file line number Diff line number Diff line change
Expand Up @@ -340,7 +340,7 @@ export default function App() {

Now the child route should be rendering through the outlet.

<img class="tutorial" src="/_docs/v7_address_book_tutorial/03.webp" />
<img class="tutorial" loading="lazy" src="/_docs/v7_address_book_tutorial/03.webp" />

## Client Side Routing

Expand Down Expand Up @@ -456,7 +456,7 @@ export default function App({ loaderData }) {

That's it! React Router will now automatically keep that data in sync with your UI. The sidebar should now look like this:

<img class="tutorial" src="/_docs/v7_address_book_tutorial/04.webp" />
<img class="tutorial" loading="lazy" src="/_docs/v7_address_book_tutorial/04.webp" />

You may be wondering why we're "client" loading data instead of loading the data on the server so we can do server-side rendering (SSR). Right now our contacts site is a [Single Page App][spa], so there's no server-side rendering. This makes it really easy to deploy to any static hosting provider, but we'll talk more about how to enable SSR in a bit so you can learn about all the different [rendering strategies][rendering-strategies] React Router offers.

Expand Down Expand Up @@ -519,13 +519,13 @@ export function HydrateFallback() {

Now if you refresh the page, you'll briefly see the loading splash before the app is hydrated.

<img class="tutorial" src="/_docs/v7_address_book_tutorial/05.webp" />
<img class="tutorial" loading="lazy" src="/_docs/v7_address_book_tutorial/05.webp" />

## Index Routes

When you load the app and aren't yet on a contact page, you'll notice a big blank page on the right side of the list.

<img class="tutorial" src="/_docs/v7_address_book_tutorial/06.webp" />
<img class="tutorial" loading="lazy" src="/_docs/v7_address_book_tutorial/06.webp" />

When a route has children, and you're at the parent route's path, the `<Outlet>` has nothing to render because no children match. You can think of [index routes][index-route] as the default child route to fill in that space.

Expand Down Expand Up @@ -565,7 +565,7 @@ export default function Home() {
}
```

<img class="tutorial" src="/_docs/v7_address_book_tutorial/07.webp" />
<img class="tutorial" loading="lazy" src="/_docs/v7_address_book_tutorial/07.webp" />

Voilà! No more blank space. It's common to put dashboards, stats, feeds, etc. at index routes. They can participate in data loading as well.

Expand Down Expand Up @@ -661,7 +661,7 @@ export default function App() {

Now navigate to the [about page][about-page] and it should look like this:

<img class="tutorial" src="/_docs/v7_address_book_tutorial/08.webp" />
<img class="tutorial" loading="lazy" src="/_docs/v7_address_book_tutorial/08.webp" />

## Layout Routes

Expand Down Expand Up @@ -798,7 +798,7 @@ export default function App() {

Now with that shuffling around done, our about page no longer loads contacts data nor is it nested inside of the sidebar layout:

<img class="tutorial" src="/_docs/v7_address_book_tutorial/09.webp" />
<img class="tutorial" loading="lazy" src="/_docs/v7_address_book_tutorial/09.webp" />

## Pre-rendering a Static Route

Expand Down Expand Up @@ -865,7 +865,7 @@ Whether you set `ssr` to `true` or `false` depends on you and your users needs.

We should be seeing our old static contact page again, with one difference: the URL now has a real ID for the record.

<img class="tutorial" src="/_docs/v7_address_book_tutorial/10.webp" />
<img class="tutorial" loading="lazy" src="/_docs/v7_address_book_tutorial/10.webp" />

Remember the `:contactId` part of the route definition in `app/routes.ts`? These dynamic segments will match dynamic (changing) values in that position of the URL. We call these values in the URL "URL Params", or just "params" for short.

Expand Down Expand Up @@ -898,7 +898,7 @@ export default function Contact({
// existing code
```

<img class="tutorial" src="/_docs/v7_address_book_tutorial/11.webp" />
<img class="tutorial" loading="lazy" src="/_docs/v7_address_book_tutorial/11.webp" />

## Throwing Responses

Expand Down Expand Up @@ -934,7 +934,7 @@ Without client side routing, the browser will serialize the `form`'s data automa

We can test this out by clicking the "New" button in our app.

<img class="tutorial" src="/_docs/v7_address_book_tutorial/12.webp" />
<img class="tutorial" loading="lazy" src="/_docs/v7_address_book_tutorial/12.webp" />

React Router sends a 405 because there is no code on the server to handle this form navigation.

Expand All @@ -959,7 +959,7 @@ export async function action() {

That's it! Go ahead and click the "New" button, and you should see a new record pop into the list 🥳

<img class="tutorial" src="/_docs/v7_address_book_tutorial/13.webp" />
<img class="tutorial" loading="lazy" src="/_docs/v7_address_book_tutorial/13.webp" />

The `createEmptyContact` method just creates an empty contact with no name or data or anything. But it does still create a record, promise!

Expand Down Expand Up @@ -1081,7 +1081,7 @@ export default function EditContact({

Now click on your new record, then click the "Edit" button. We should see the new route.

<img class="tutorial" src="/_docs/v7_address_book_tutorial/14.webp" />
<img class="tutorial" loading="lazy" src="/_docs/v7_address_book_tutorial/14.webp" />

## Updating Contacts with `FormData`

Expand Down Expand Up @@ -1110,7 +1110,7 @@ export async function action({

Fill out the form, hit save, and you should see something like this! <small>(Except easier on the eyes and maybe with the patience to cut watermelon.)</small>

<img class="tutorial" src="/_docs/v7_address_book_tutorial/15.webp" />
<img class="tutorial" loading="lazy" src="/_docs/v7_address_book_tutorial/15.webp" />

## Mutation Discussion

Expand Down Expand Up @@ -1203,7 +1203,7 @@ export async function action() {

Now when we click "New", we should end up on the edit page:

<img class="tutorial" src="/_docs/v7_address_book_tutorial/16.webp" />
<img class="tutorial" loading="lazy" src="/_docs/v7_address_book_tutorial/16.webp" />

## Active Link Styling

Expand Down Expand Up @@ -1253,7 +1253,7 @@ export default function SidebarLayout({

Note that we are passing a function to `className`. When the user is at the URL that matches `<NavLink to>`, then `isActive` will be true. When it's _about_ to be active (the data is still loading) then `isPending` will be true. This allows us to easily indicate where the user is and also provide immediate feedback when links are clicked but data needs to be loaded.

<img class="tutorial" src="/_docs/v7_address_book_tutorial/17.webp" />
<img class="tutorial" loading="lazy" src="/_docs/v7_address_book_tutorial/17.webp" />

## Global Pending UI

Expand Down Expand Up @@ -1298,7 +1298,7 @@ export default function SidebarLayout({

In our case, we add a `"loading"` class to the main part of the app if we're not idle. The CSS then adds a nice fade after a short delay (to avoid flickering the UI for fast loads). You could do anything you want though, like show a spinner or loading bar across the top.

<img class="tutorial" src="/_docs/v7_address_book_tutorial/18.webp" />
<img class="tutorial" loading="lazy" src="/_docs/v7_address_book_tutorial/18.webp" />

## Deleting Records

Expand Down Expand Up @@ -1448,7 +1448,7 @@ export async function loader({
// existing code
```

<img class="tutorial" src="/_docs/v7_address_book_tutorial/19.webp" />
<img class="tutorial" loading="lazy" src="/_docs/v7_address_book_tutorial/19.webp" />

Because this is a `GET`, not a `POST`, React Router _does not_ call the `action` function. Submitting a `GET` `form` is the same as clicking a link: only the URL changes.

Expand Down Expand Up @@ -1766,13 +1766,13 @@ export default function SidebarLayout({

You should now have a nice spinner on the left side of the search input.

<img class="tutorial" src="/_docs/v7_address_book_tutorial/20.webp" />
<img class="tutorial" loading="lazy" src="/_docs/v7_address_book_tutorial/20.webp" />

## Managing the History Stack

Since the form is submitted for every keystroke, typing the characters "alex" and then deleting them with backspace results in a huge history stack 😂. We definitely don't want this:

<img class="tutorial" src="/_docs/v7_address_book_tutorial/21.webp" />
<img class="tutorial" loading="lazy" src="/_docs/v7_address_book_tutorial/21.webp" />

We can avoid this by _replacing_ the current entry in the history stack with the next page, instead of pushing into it.

Expand Down Expand Up @@ -1880,7 +1880,7 @@ export async function action({

Alright, we're ready to click the star next to the user's name!

<img class="tutorial" src="/_docs/v7_address_book_tutorial/22.webp" />
<img class="tutorial" loading="lazy" src="/_docs/v7_address_book_tutorial/22.webp" />

Check that out, both stars automatically update. Our new `<fetcher.Form method="post">` works almost exactly like the `<Form>` we've been using: it calls the action and then all data is revalidated automatically — even your errors will be caught the same way.

Expand Down

0 comments on commit 33165a2

Please sign in to comment.