Получение списка покемонов с использованием PokeAPI с Remix Framework

Несколько недель назад Документация ReactJS получила серьезное обновление. Эта новая документация улучшается с помощью таких примеров, как диаграммы, иллюстрации, задачи и более 600 новых интерактивных примеров. Это будет очень полезно для новичков в ReactJS и для опытных разработчиков ReactJS, которые хотят отточить свои глубокие знания о том, как работает React.

Хотя в новой документации есть много замечательных аспектов, я хотел бы сосредоточиться на одном: разделе Начало нового проекта React.

Существенным изменением в разделе Начало нового проекта React является то, что в официальной документации ReactJS больше не упоминается Create-React-App (CRA). Вместо этого они рекомендуют фреймворки React производственного уровня, такие как Next.js, Gatsby и Remix.

В их предыдущей унаследованной документации единственными рекомендуемыми фреймворками React были Next.js и Gatsby. Однако в новой документации они представили новый рекомендуемый фреймворк под названием Remix.

Я создам пример фрагмента кода в Remix и эквивалентный пример в Next.js. Поскольку Next.js уже довольно давно является частью экосистемы внешнего интерфейса, многие инженеры внешнего интерфейса будут лучше знакомы с его концепциями.

Что такое ремикс?

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

Ключевые особенности ремикса

Я впервые попробовал Remix, чтобы создать простой список покемонов, который извлекает данные из PokeAPI. В этой статье я объясню несколько вещей о Remix и о том, что я узнал, используя его в первый раз.

Конечный результат этого проекта вы можете посмотреть по этой ссылке.

Загрузка данных

Одной из основных функций Remix является упрощение взаимодействия с сервером для передачи данных в компоненты. Это эквивалентно функции getServerSideProps в Next.js.

Здесь я обрабатываю две функции для этого веб-сайта:

  1. Получение списка покемонов для первоначального рендера.
  2. Получение следующего покемона для разбиения на страницы.
export const loader = async ({ request }: LoaderArgs) => {
  // pagination handling
  const url = new URL(request.url);
  const query = url.searchParams.get("next");
  if (query) {
    const fetchPoke = await fetch(query);
    const fetchPokeJson = await fetchPoke.json();
    return json(fetchPokeJson);
  }
  // end of pagination handling

  // initial fetch
  const fetchPoke = await fetch("https://pokeapi.co/api/v2/pokemon");
  const fetchPokeJson = await fetchPoke.json();
  return json(fetchPokeJson);
  // end of initial fetch
};
interface LoaderData {
 count: number;
 next: string;
 results: {
  name: string;
  url: string;
 }[];
}

import { useLoaderData } from "@remix-run/react";

export default function PokeList() {
 // Obtain the data returned from the server using useLoaderData().
 const pokeData = useLoaderData() as LoaderData;

 return (
  <SimpleGrid
   cols={4}
   breakpoints={[
    { maxWidth: "sm", cols: 2 },
    { maxWidth: "md", cols: 3 },
    { maxWidth: "lg", cols: 4 },
   ]}
  >
   {poke.results.map((x, y) => {
    return (
     <Card key={x.name}>
      <Card.Section>
       <Center>
        <Image
         withPlaceholder
         width={120}
         height={120}
         src={`https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/${y + 1
          }.png`}
         alt={x.name}
        />
       </Center>
      </Card.Section>
      <Text>{x.name}</Text>
     </Card>
    );
   })}
  </SimpleGrid>
 );
}

В Next.js вы можете быть знакомы с похожей концепцией:

function Page({ data }) {
  // Render data...
}

// This gets called on every request
export async function getServerSideProps() {
  // Fetch data from external API
  const res = await fetch(`https://.../data`)
  const data = await res.json()

  // Pass data to the page via props
  return { props: { data } }
}

Маршрутизация

Remix также использует систему маршрутизации на основе файлов, аналогичную другим метафреймворкам в текущей экосистеме внешнего интерфейса. Однако внутренняя маршрутизация Remix построена поверх react-router-dom. Маршрутизация, возможно, самая важная концепция для понимания в Remix. Все начинается с ваших маршрутов: компилятор, первоначальный запрос и почти каждое последующее взаимодействие с пользователем.

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

Вот пример структуры маршрутизации в Remix. Каждый новый файл, который вы создаете в папке маршрутов, будет доступен через URL-адрес страницы, поэтому важно понимать основные концепции маршрутизации Remix.

|--app
   |--routes
      |--$name.tsx -> https://example.com/*
      |--index.tsx -> https://example.com
      |--PokeList.tsx -> https://example.com/pokelist

Вот эквивалентная структура маршрутизации в Next.js:

|--pages
   |--index.tsx -> https://example.com
   |--PokeList.tsx -> https://example.com/pokelist
   |--[name]
      |--index.tsx -> https://example.com/*

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

  • Макеты для отображения на странице
  • Пакеты JavaScript с разделением кода для загрузки
  • Зависимости данных этих макетов

Поскольку Pokelist — это маршрут, да, вы можете получить доступ к URL по этой ссылке.

В некоторых случаях прямой доступ к этим маршрутам может быть приемлемым, но в моем случае я запрещаю прямой доступ к URL-адресу, потому что эти маршруты вызовут ошибку. Загрузчик данных для получения списка покемонов находится в routes/index.tsx.

/**
 * prevent direct access to the url
 */
export const loader = async () => {
 return redirect('/');
};

const PokeList = () => {
 ...
 ...
};

export default PokeList;

Параметры рендеринга

Согласно Twitter thread от сопровождающего самого Remix, Remix в настоящее время поддерживает только рендеринг на стороне клиента (CSR) и рендеринг на стороне сервера (SSR) и не имеет таких функций, как генерация статического сайта (SSG). В результате он обычно ожидает, что у вас есть сервер.

Стиль

В современной экосистеме существуют десятки подходов и фреймворков для стилизации. Remix поддерживает многие из них «из коробки», но фреймворки, которые требуют прямой интеграции с компилятором Remix и ожидают, что Remix автоматически вставит стили на страницу, сейчас не работают.

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

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

Одним из примеров является библиотека Mantine; при использовании Mantine в Remix рендеринг сервера потоковой передачи не будет работать. Вот руководство для получения дополнительной информации.

Граница ошибки

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

export const loader = async ({ params }: LoaderArgs) => {
    const fetchData = await fetch(`https://pokeapi.co/api/v2/pokemon/${params.name}`);
    if (fetchData.status !== 200) {
        throw new Error();
    }
    const fetchJson = await fetchData.json();
    return json(fetchJson);
}

// your error boundary
export function ErrorBoundary({ error }) {
 // log your error 
 yourLogger(error);
 return (
  <Container>
   <Stack>
    <Alert color={'red'}>
     Error
    </Alert>
   </Stack>
  </Container>
 );
}

const PokeDetail = () => {
  ...
  ...
}

export default PokeDetail;

Заключение

Remix — еще один метафреймворк, появившийся в экосистеме ReactJS. Теперь у нас есть три варианта, рекомендуемые документацией ReactJS: Next.js, Gatsby и Remix.

По моему личному мнению, после того, как я впервые попробовал Remix, я чувствую, что этот фреймворк имеет более высокую кривую обучения, чем Next.js.

Если ваш проект или компания в настоящее время создает собственную внутреннюю структуру с зависимостями от react-router-dom, вам следует проверить Remix, так как теперь документация ReactJS рекомендует его для создания нового приложения React.

Ресурсы