Remix prefetch: Заблаговременная выборка данных

Remix — это JavaScript-фреймворк для серверного рендеринга edge-first, построенный на React, который позволяет создавать полнофункциональные веб-приложения с возможностями SSR (рендеринг на стороне сервера) и фронтенда. На фронтенде он действует как фреймворк React более высокого уровня, который предлагает SSR (рендеринг на стороне сервера), маршрутизацию на основе файлов, вложенные маршруты и загрузчики, префетч, оптимистичный UI и многое другое. Он рендерит данные на сервере и отправляет html на сторону клиента в качестве ответа.

Что мы создаем

В этой статье мы рассмотрим интересную возможность, которую предоставляет нам Remix — предварительную выборку данных. Хотя реализовать эту функцию в приложении Remix очень просто, она улучшает UX и значительно оптимизирует работу приложения. Когда пользователь фокусируется на ссылке или нажимает на нее мышью, скорее всего, он хочет перейти по ней. Поэтому мы будем получать данные до того, как они перейдут на страницу.

Мы будем потреблять данные из rickandmortyapi, где мы будем получать все символы из rickymorty и реализовывать предварительную выборку, когда пользователь попытается перейти по ссылке (до перехода на индивидуальную детальную страницу), при наведении мышки мы будем получать данные заранее.

Создание нашего проекта

Чтобы создать новое приложение Remix, все, что нам нужно сделать, — это выполнить следующую команду в терминале.

npx create-remix@latest
Войти в полноэкранный режим Выйти из полноэкранного режима

Это создаст для нас шаблон remix-приложения для начала и задаст несколько вопросов о среде разработки, в которой мы хотим настроить наш проект.

Мы ответим на все вопросы, как показано ниже

# 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
Войти в полноэкранный режим Выйти из полноэкранного режима

До этого момента мы закончили с настройкой. Давайте начнем создавать интерфейс для нашего приложения и введем некоторые данные, чтобы посмотреть.

Добавление макета

Прежде чем мы начнем, я добавлю компонент макета, чтобы мы могли обернуть все наше приложение этим компонентом. Это будет что-то вроде обертки провайдера для всего нашего приложения.

//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;

Вход в полноэкранный режим Выход из полноэкранного режима

Домашняя страница

Нам определенно нужны некоторые данные для отображения в нашем пользовательском интерфейсе. Для этого мы будем использовать открытый публичный API от rickyandmortyapi. Это обеспечит нас всеми персонажами из фильма.

Этого можно достичь с помощью новой асинхронной функции loader, которая выполняется на сервере и отвечает за предварительную выборку данных перед отрисовкой компонента на сервере. Функция loader сопровождается новым хуком useLoaderData, который может быть использован внутри нашего компонента для получения доступа к загруженным данным, возвращаемым функцией loader после получения данных.

/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;
};

Вход в полноэкранный режим Выход из полноэкранного режима

После настройки загрузчика мы можем получить доступ к данным, возвращаемым этим загрузчиком, используя хук useLoaderData в нашем компоненте.

Прежде чем мы перейдем к отображению данных в нашем пользовательском интерфейсе, нам нужно добавить интерфейс typescript, чтобы сообщить 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;
}
Вход в полноэкранный режим Выход из полноэкранного режима

Теперь мы можем использовать эти данные внутри нашего компонента.

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>
  );
}

Вход в полноэкранный режим Выход из полноэкранного режима

Вы также могли заметить, что мы использовали функцию ссылок из Remix, где мы добавили ссылку на динамическую страницу детального экрана to={character.id}, давайте продолжим и создадим нашу детальную страницу.

Детальная страница

Чтобы получить данные для запрошенной страницы детализации, мы можем посмотреть документацию о том, как нам нужно запросить конкретного персонажа с ID. Таким образом, это будет выглядеть следующим образом

https://rickandmortyapi.com/api/character/{id}
Вход в полноэкранный режим Выйти из полноэкранного режима

Для того чтобы получить идентификатор из списка персонажей мультфильма, мы можем использовать свойство params, передать его внутрь нашего Loader и сделать запрос к API.

export const loader: LoaderFunction = async ({ params }) => {
  const fetchData = await fetch(
    `https://rickandmortyapi.com/api/character/${params.characterId}`
  );
  const response = await fetchData.json();
  return response;
};
Вход в полноэкранный режим Выход из полноэкранного режима

Теперь мы можем взять данные, полученные от Loader, и заполнить ими нашу страницу с помощью хука useLoaderData.

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>
  );
}
Вход в полноэкранный режим Выход из полноэкранного режима

Итак, до сих пор мы подготовили все необходимое для реализации предварительной выборки данных. Как уже было сказано, это очень просто и для этого требуется всего одна строчка в реквизите. Мы добавим реквизит к нашему компоненту link.

Добавление предварительной выборки

<Link
style={{ textDecoration: 'none' }}
to={character.id}
prefetch="intent"
>Content inside a link wrapper</Link>
Вход в полноэкранный режим Выйти из полноэкранного режима

Основным преимуществом этого является устранение задержки в 1-2 секунды при получении данных с нашего сервера. Наряду с такими тонкими преимуществами, как уважение заголовков кэша HTTP, выполнение работы во время простоя браузера, использование потока, отличного от потока вашего приложения, и многое другое. Link может автоматически выполнять предварительную выборку всех ресурсов, необходимых следующей странице: модули JavaScript, таблицы стилей и данные. Этот параметр контролирует, если и когда это произойдет.

Мы можем передать три различных варианта предварительной выборки.

  • «none»

Поведение по умолчанию. Это предотвратит любую предварительную выборку. Это рекомендуется при ссылке на страницы, требующие пользовательской сессии, которые браузер все равно не сможет предварительно получить.

  • «намерение»

Рекомендуется, если вы хотите использовать предварительную выборку. Выполняет выборку, когда Remix считает, что пользователь намерен посетить ссылку. На данный момент поведение простое: если пользователь наведет курсор или сфокусируется на ссылке, то будет произведена предварительная выборка ресурсов. В будущем мы надеемся сделать это еще умнее. Ссылки с большими областями клика/паддинга получают небольшую фору. Стоит отметить, что при использовании prefetch=»intent» элементы будут вставлены при наведении/фокусировке и удалены при потере наведения/фокусировки. Без соответствующих заголовков cache-control в ваших загрузчиках это может привести к повторной загрузке prefetch, если пользователь постоянно наводит курсор на ссылку.

  • «render»

Захватывает, когда ссылка отображается.

Это взято из официальной документации Remix. Вы можете найти ее здесь. Вы также можете предварительно забирать все активы, такие как данные, модули, css до времени, подробнее об этом здесь.

Remix использует кэш браузера под капотом для предварительной выборки HTML, что очень здорово.

Заключение

Remix — это потрясающий фреймворк, как только вы проникнитесь им, вы полюбите его еще больше. Если вы раздумываете, стоит ли вам попробовать Remix для своего следующего проекта? Да, пожалуйста, попробуйте, это потрясающий опыт разработчика (DX).

Вы также можете добиться этого, используя функцию React-query Prefetching внутри приложения React. Подробнее смотрите здесь.

Код для этого можно найти в репозитории Github здесь.

Счастливого кодинга!

Оцените статью
Procodings.ru
Добавить комментарий