До сих пор мы рассматривали статическую загрузку данных и загрузку данных из нашей базы данных, но еще одним широко используемым методом является загрузка из внешнего API.
В нашем случае мы запросим API Pokémon, чтобы получить список всех покемонов. Мы поймаем их и, щелкнув на одном, увидим соответствующую картинку.
Я буду использовать проект, который мы создали до сих пор.
Если вы хотите кодить вместе со мной, начните с этого репозитория GitHub.
Создание вызовов API Pokémon
Первое, что мы хотим сделать, это добавить новый файл сервера. В нашем случае этот файл будет довольно простым, но мы можем захотеть повторно использовать некоторые из этих вызовов позже.
Создайте файл pokemon.server.ts
внутри вашего каталога app/models
.
Здесь нам понадобятся два файла: один для получения основного списка всех покемонов, а другой — для получения подробной информации о конкретном покемоне на основе его имени.
Первый — самый простой:
export async function getPokemons() {
const res = await fetch(
'https://pokeapi.co/api/v2/pokemon?limit=100000&offset=0'
).then((res) => res.json());
return res.results;
}
Технически мы могли бы также вернуть хук await fetch, но поскольку нас интересуют только результаты, мы вернем их напрямую.
Примечание: Pokemon API возвращает результаты постранично. Поэтому здесь нам нужен доступ к
res.results
.
Вторая часть заключается в получении покемона по его имени.
export async function getPokemon(name: string | undefined) {
const res = await fetch(`https://pokeapi.co/api/v2/pokemon/${name}`).then(
(res) => res.json()
);
return {
name: name,
img: res.sprites.front_default,
};
}
Здесь мы применяем тот же прием — возвращаем только то, что нам нужно. Вы можете добавить столько полей, сколько захотите, из объекта ответа.
Создание обзорного списка покемонов
Теперь, когда у нас есть доступ к данным, мы можем начать их использовать.
Создайте папку Pokemon
внутри каталога app/routes
.
И внутри нее создайте файл index.tsx
, который будет нашим файлом обзора.
Затем мы можем использовать TypeScript для добавления загрузчика с сохранением типа.
import { json } from "@remix-run/node";
import { Link, useLoaderData } from "@remix-run/react";
import { getPokemons } from "~/models/pokemon.server";
type LoaderData = {
data: Awaited<ReturnType<typeof getPokemons>>;
};
export const loader = async () => {
return json<LoaderData>({
data: await getPokemons(),
});
};
export default function Posts() {
const { data } = useLoaderData() as LoaderData;
return (
<main className="mx-auto max-w-4xl">
<h1 className="my-6 border-b-2 text-center text-3xl">
Which Pokémon do you want to catch?</h1>
<ul className='mx-auto text-center'>
{data.map((pokemon) => (
<li key={pokemon.name}>
<Link
to={pokemon.name}
className="text-blue-600 underline"
>
{pokemon.name}
</Link>
</li>
))}
</ul>
</main>
);
}
Основными частями, на которые следует обратить внимание, являются собственно функция loader
и вызов этой функции внутри компонента.
Она запросит наш только что созданный файл сервера и запросит всех покемонов.
Затем мы выводим их в виде списка, в результате чего получается следующее:
Также обратите внимание, что мы используем компонент link для ссылки на каждого покемона на основе его имени.
Мы будем использовать эту информацию в следующей части.
Рендеринг отдельных страниц с покемонами
Как мы читали выше, мы ссылаемся на каждого покемона, и это сгенерирует URL, как показано ниже: /pokemon/${name}
.
Используя это, мы можем добавить файл $name.tsx
в нашу директорию pokemon
.
Обратите внимание, что $name
— это параметр, который вы хотите прочитать позже.
Настройка этого файла очень похожа на страницу обзора, но в нем используется другая функция.
import { json, LoaderFunction } from "@remix-run/node";
import { useLoaderData } from "@remix-run/react";
import { getPokemon } from "~/models/pokemon.server";
type LoaderData = {
pokemon: Awaited<ReturnType<typeof getPokemon>>;
};
export const loader: LoaderFunction = async ({params,}) => {
return json({
pokemon: await getPokemon(params.name),
});
};
export default function PostSlug() {
const { pokemon } = useLoaderData() as LoaderData;
return (
<main className="mx-auto max-w-4xl">
<h1 className="my-6 border-b-2 text-center text-3xl">
You caught: {pokemon.name}
</h1>
<img className='mx-auto' src={pokemon.img} />
</main>
);
}
И теперь, когда мы нажимаем на нашего покемона, мы получаем следующую страницу.
Это более подробный способ загрузки данных из внешнего API. Вы всегда можете использовать конечные точки непосредственно в своих функциях загрузчика файлов.
Однако, извлекая их, вы делаете задел на будущее.
Полный код можно найти на GitHub.
Спасибо, что прочитали, и давайте общаться!
Спасибо, что читаете мой блог. Не стесняйтесь подписываться на мою рассылку по электронной почте и подключайтесь к Facebook или Twitter.