Remix prefetch: Fetch data ahead of time
Tags: typescript, remix, react, javascript
Published: 2022-05-29 05:13:00

Remix is an edge-first server-side rendering JavaScript framework built on React that allows us to build full-stack web applications with the capabilities of SSR (server-side rendering) and frontend. On the frontend, it acts as a higher level React framework that offers SSR (server-side rendering), file-based routing, nested routes and a loaders, prefetch, optimistic UI and more. It renders the data on the server and sends the html to client side as a response.


## What are we building

In this article we will be exploring out an interesting feature Remix provides us with **data prefetching**. Although it's dead simple easy to implement this feature inside remix application this enhances UX and optimize the application performance a lot. When a user focuses or mouses-over a link, it's likely they want to go there. So we will prefetch the data before they're going to the page. 

We will consume data from [rickandmortyapi](https://rickandmortyapi.com/) where we will fetch all the characters from rickymorty and implement prefetch when the user tries to visit the link (before going to individual detail page) with a hover we will fetch data ahead of time.

## Creating our project

To create a new Remix app, all we have to do is start by running the below command in our terminal.

```
npx create-remix@latest
```

This will creates a boilerplate remix application for us to start with and ask us few questions on the dev environment we want our project to set-up. 

We will answer all the questions as below


```shell
# Answer the basic questions

**Where would you like to create your app?** remix-prefetch
**What type of app do you want to create?** Just the basics
**Where do you want to deploy? Choose Remix if you're unsure; it's easy to change deployment targets**. Remix App Server
**Do you want me to run `npm install`?** Yes
**TypeScript or JavaScript?** TypeScript

# changing to project directory

cd remix-prefetch

# run the application

npm run dev
```


Until this point we are all done with out setup. Lets start creating an interface for our application and we can populate some data to take a look.

## Adding a Layout

Before we begin i will add up a layout component so that we can wrap all of our application with this component. This acts something like a provider wrapper for our entire application. 

```typescript
//components/layout.tsx
const Layout = ({ children }: HTMLBodyElement) => {
  return (
    <>
      <div style={{ maxWidth: '900px', margin: '0 auto' }}>
        <h1>Rick and Morty App</h1>
        <br />
        <div>{children}</div>
      </div>
    </>
  );
};

export default Layout;

```

## Homepage

We definitely need some data to showed in our UI. For that we will be using an open public API from [rickyandmortyapi](https://rickandmortyapi.com/).  This will provide us with all the characters from the movie. 


This is achievable using a new asynchronous function called **loader** that runs on the server and is solely responsible for prefetching data before the component is rendered on the server. The loader function is accompanied by a new hook called **useLoaderData** that can be utilized inside of our component to get access to the loaded data that is returned by the loader function after the data has been fetched.

```typescript
/app/routes/index.tsx
export const loader: LoaderFunction = async () => {
  const fetchData = await fetch('https://rickandmortyapi.com/api/character/');
  const response = await fetchData.json();
  const data = response.results;
  return data;
};

```

After setting up a loader, we can access whatever data is returned by this loader using the useLoaderData hook in our component.

Before we move ahead to list the data in our UI, we need to add a typescript interface just to tell typescript what type of interface type we are expecting.

```typescript
export interface Characters {
  id: number;
  name: string;
  status: string;
  species: string;
  type: string;
  gender: string;
  origin: Location;
  location: Location;
  image: string;
  episode: string[];
  url: string;
  created: Date;
}

interface Location {
  name: string;
  url: string;
}
```

We can now consume this data inside of our component. 

```typescript
export default function Index() {
  const dataList = useLoaderData();
  return (
    <Layout>
      <div>
        {dataList.map((character: Characters) => (
          <div
            key={character.id}
            style={{
              marginBottom: '30px',
              border: '1px solid #e7e7e7',
              padding: '20px',
            }}
          >
            <Link
              style={{ textDecoration: 'none' }}
              to={character.id}
            >
              <h3> {character.name}</h3>
              <div style={{ display: 'flex' }}>
                <img src={character.image} alt={character.name} />
                <ul style={{ listStyle: 'none' }}>
                  <li style={{ marginBottom: '5px' }}>
                    Species: {character.species}
                  </li>
                  <li style={{ marginBottom: '5px' }}>
                    Status : {character.status}
                  </li>
                  <li style={{ marginBottom: '5px' }}>
                    Gender: {character.gender}
                  </li>
                </ul>
              </div>
            </Link>
          </div>
        ))}
      </div>
    </Layout>
  );
}

```

With all that in place you may also have noticed we have used a link feature from Remix where we added link to a dynamic page of detail screen               **to={character.id}** lets go ahead and create our detail page.

## Detailpage

To fetch the data for the requested detail page we can see the documentation on how we need to request for specific character with ID. So, it would look like 

```shell
https://rickandmortyapi.com/api/character/{id}
```

In order to grab the id clicked from the list of cartoon characters we can make the use of params property and pass that in inside of our **Loader** and make a request to the API.

```typescript
export const loader: LoaderFunction = async ({ params }) => {
  const fetchData = await fetch(
    `https://rickandmortyapi.com/api/character/${params.characterId}`
  );
  const response = await fetchData.json();
  return response;
};
```
We can now take the data returned from the Loader and populate it inside of our page with **useLoaderData** hook.

```typescript
export default function Index() {
  const characterDetail: Characters = useLoaderData();
  return (
    <Layout>
      <div>
        <div>
          <Link to="/">go back</Link>
        </div>
        <br />
        <img src={characterDetail.image} alt="" />
        <h1>{characterDetail.name}</h1>
        <ul style={{ listStyle: 'none', paddingLeft: '0px' }}>
          <li style={{ marginBottom: '10px' }}>
            Species: {characterDetail.species}
          </li>
          <li style={{ marginBottom: '10px' }}>
            Status : {characterDetail.status}
          </li>
          <li style={{ marginBottom: '10px' }}>
            Gender: {characterDetail.gender}
          </li>
        </ul>
      </div>
    </Layout>
  );
}
```

So, until now we have prepared all things needed to implement data prefetching. As said this is dead simple and just takes one line of prop achieve this. We will add a prop to our link component.


## Adding prefetch

```typescript
<Link
style={{ textDecoration: 'none' }}
to={character.id}
prefetch="intent"
>Content inside a link wrapper</Link>
```

The main advantage of this is this eliminates about 1-2seconds of latency delay to fetch data from our server. Along with the subtle benefits like respecting HTTP cache headers, doing the work in browser idle time, using a different thread than your app and more. **Link** can automatically prefetch all the resources the next page needs: JavaScript modules, stylesheets, and data. This prop controls if and when that happens.


We can pass three different options to prefetch.

- **"none"** 

Default behavior. This will prevent any prefetching from happening. This is recommended when linking to pages that require a user session that the browser won't be able to prefetch anyway.

- **"intent"** 

Recommended if you want to prefetch. Fetches when Remix thinks the user intends to visit the link. Right now the behavior is simple: if they hover or focus the link it will prefetch the resources. In the future we hope to make this even smarter. Links with large click areas/padding get a bit of a head start. It is worth noting that when using prefetch="intent", <link rel="prefetch"> elements will be inserted on hover/focus and removed if the <Link> loses hover/focus. Without proper cache-control headers on your loaders this could result in repeated prefetch loads if a user continually hovers on and off a link.

- **"render"** 

Fetches when the link is rendered.

> This is taken from official documentation of Remix. You can find it [here](https://remix.run/docs/en/v1/api/remix#link). You can also prefetch all the assets like data, modules, css before time please lean more about it [here](https://remix.run/docs/en/v1/api/remix#prefetchpagelinks-).

Remix uses browser cache under the hood for prefetching HTML which is really cool. 

## Conclusion

Remix is an awesome framework once you get inside it the more you love it. If you’re wondering whether or not you should try Remix for your next project? Yes please go ahead with it, its an awesome developer experience(DX). 

> You can also achieve this using React-query Prefetching feature inside of React application. See more [here](https://react-query.tanstack.com/guides/prefetching#manually-priming-a-query).

You can find the code for this in the Github repository [here](https://github.com/ishandotjs/remix-prefetch).

Happy Coding!