Как создать приложение для Pokemon с помощью GraphQL и Apollo
Pokemon - это японская медиа-франшиза, состоящая из видеоигр, анимационных сериалов и фильмов, карточной игры и других связанных с ней медиа.
В этом блоге мы будем использовать Pokemon GraphQL API, который предоставляет нам данные о разных покемонах.
Мы будем использовать Apollo и GraphQL для обработки выборки данных и React для создания нашего интерфейсного приложения.
Не беспокойтесь, если вы не знакомы с этими технологиями, я расскажу вам об основах по мере чтения.
Предварительные условия
Для дальнейшего использования они должны быть на вашем компьютере:
- Nodejs v18+
- Редактор кода
- Веб-браузер.
Давайте перейдем к созданию нашего приложения React.
Настройка приложения React
Чтобы создать приложение React, перейдите в свой терминал и воспользуйтесь командной строкой. Откройте командную строку и выберите удобное расположение для создания проекта React. Давайте начнем с рабочего стола.
cd Desktop
Приведенная выше команда перейдет на ваш рабочий стол.
npm create vite@latest pokemon-app -- --template react
npm create vite@latest
начнет создавать новый проект с использованием Vite. Но мы добавили название нашего проекта (pokemon-app
) и технологию или структуру, которую будет использовать наше приложение (-- -- template react
).
Вы можете установить другой шаблон, например svelte
, vanilla
или vue
, и проект будет создан с использованием этой структуры. Подробнее о Vite читайте на его официальном сайте.
После установки Vite выполните следующие команды:
cd pokemon-app
npm install
npm run dev
Мы воспользуемся приведенными выше командами, чтобы завершить настройку React.
Запустите первую команду cd pokemon-app
, чтобы перейти к папке pokeman-app.
Запустите code .
. чтобы открыть папку в редакторе кода.
Установите флажок «Доверять автору», если он появится.
Откройте терминал редактора кода. Если вы используете VSCode в Windows, ярлык — Ctrl + `
.
Запустите две другие команды в терминале одну за другой.
npm install
npm run dev
Сейчас ваш проект должен быть запущен в браузере.
Мы будем управлять получением наших данных с помощью GraphQL и Apollo.
Как использовать GraphQL и Apollo
GraphQL - это язык запросов для API и среда выполнения для выполнения запросов с вашими существующими данными. Он позволяет вам запрашивать только те данные, которые вам нужны в вашем приложении, и ничего больше, что делает его очень эффективным и гибким.
Apollo - это библиотека управления состоянием, которая позволяет вам управлять локальными и удаленными данными с помощью GraphQL. Ее можно использовать для извлечения, кэширования и изменения данных приложения, при этом автоматически обновляя пользовательский интерфейс.
Давайте установим нужные вам пакеты.
Установка пакетов
Запустите приведенную ниже команду в своем терминале, чтобы установить клиент Apollo.
npm install @apollo/client
Перейдите к вашему основному main.jsx и импортируйте эти:
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App.jsx";
import {
ApolloProvider,
ApolloClient,
InMemoryCache,
} from "@apollo/client";
import "./index.css";
Вы импортировали React и ReactDOM для манипуляций с DOM.
ApolloClient
отвечает за выборку данных вашего приложения и управление состоянием. Он обрабатывает отправку запросов и мутаций GraphQL на ваш сервер GraphQL и кэширует результаты.
ApolloProvider
будет использоваться для оболочки вашего приложения React, чтобы предоставить экземпляр Apollo Client всем вашим компонентам, чтобы ваше приложение могло получить доступ к данным, полученным через Apollo Client.
InMemoryCache
— это реализация кэша для хранения результатов запросов GraphQL в памяти для эффективного доступа и извлечения.
Вы также импортировали index.css для оформления своего приложения.
Как создать Client Apollo
const client = new ApolloClient({
uri: "https://graphql-pokemon2.vercel.app/",
cache: new InMemoryCache(),
});
Приведенный выше код создает новый экземпляр ApolloClient
с некоторыми конфигурациями:
uri
: Здесь указан URL-адрес вашей конечной точки GraphQL API. Это конечная точка, в которую ваш клиент Apollo будет отправлять запросы GraphQL и изменения.cache
: Это позволяет клиенту Apollo использовать кэш в памяти для доступа к данным и сохранения результатов запросов GraphQL, что снижает необходимость в повторном извлечении данных с сервера.
Теперь вы можете использовать компонент <App />
в ApolloProvider
:
ReactDOM.createRoot(document.getElementById("root")).render(
<React.StrictMode>
<ApolloProvider client={client}>
<App />
</ApolloProvider>
</React.StrictMode>
);
Обратите внимание, что реквизиты client
также были переданы для предоставления вашему приложению конфигурации ApolloClient
.
Перейдите к компоненту App.jsx и введите следующее:
import React from "react";
import { PokemonsContainer } from "./components/PokemonsContainer";
export default function App() {
return (
<main>
<PokemonsContainer />
</main>
);
}
Вы импортировали React и PokemonsContainer
будет создан. Компонент PokemonsContainer
был заключен в основной тег и будет отображаться при вставке компонента в DOM.
Давайте создадим компонент PokemonsContainer
в файле, расположенном в папке компонентов. То есть:
📂 src/comComponents/PokemonsContainer.jsx
Компонент Pokemon Container
import React from "react";
import { useQuery } from "@apollo/client";
import { Pokemon } from "../components/Pokemon";
import { GET_POKEMONS } from "../graphql/get-pokemons";
UseQuery
из @apollo/client
используется для выполнения запросов в приложении Apollo. Для этого вызывается метод useQuery()
и строка запроса GraphQL передается в качестве аргумента. Когда ваш компонент визуализируется, useQuery
возвращает объект из клиента Apollo, который содержит свойства loading
, error
и data
, которые вы можете использовать для визуализации вашего пользовательского интерфейса.
Компонент Pokemon
был импортирован для рендеринга пользовательского интерфейса для Pokemon, он будет создан в ближайшее время.
GET_POKEMONS
также был импортирован. Он будет содержать запрос GraphQL.
После импорта вышеуказанных функций продолжайте создавать свою страницу.
export function PokemonsContainer() {
const { loading, error, data } = useQuery(GET_POKEMONS, {
variables: { first: 5 },
});
if (loading) return <p>Loading...</p>;
if (error) return <p>Error: {error.message}</p>;
const pokemons = data?.pokemons || [];
return (
<div className="container">
{pokemons &&
pokemons.map((pokemon) => (
<Pokemon key={pokemon.id} pokemon={pokemon} />
))}
</div>
);
}
Как упоминалось ранее, useQuery
возвращает объект из Apollo Client, который содержит свойства loading
, error
и data
. Здесь они деструктурированы, поэтому вы можете получить к ним доступ на странице.
Обратите внимание, что мы предоставляем параметр конфигурации (variables
) для перехватчика useQuery
. { variables: { first: 5 } }
также были переданы в качестве второго аргумента. Опция variables
— это объект, который содержит все переменные, которые мы хотим передать в наш запрос GraphQL. В этом случае мы передали объект { first: 5 }
, чтобы указать, что нам нужны первые пять покемонов.
Если запрос все еще загружается, <p>Loading...</p>
возвращается для обозначения пользователя, а <p>Error: {error.message}</p>
будет возвращен в случае ошибки.
Константа pokemons
была создана для хранения значения свойства Pokemons объекта данных. Если data.pokemons
недоступен, константа pokemons
будет пустым массивом.
div
возвращается с classname
container
, который проверяет, доступен ли pokemons
, и сопоставляет массив с компонентом Pokemon
.
Давайте создадим компонент Pokemon
:
📂src/components/Pokemon.jsx
Компонент Pokemon
import React from "react";
export function Pokemon({ pokemon }) {
return (
<div className="pokemon">
<div className="pokemon__name">
<p>{pokemon.name}</p>
</div>
<div className="pokemon__meta">
<span>{pokemon.maxHP}</span>
<span>{pokemon.maxCP}</span>
</div>
<div className="pokemon__image">
<img src={pokemon.image} alt={pokemon.name} />
</div>
<div className="pokemon__attacks">
{pokemon.attacks.special.slice(0, 3).map((attack) => (
<span key={`${attack.name}-${attack.damage}`}>{attack.name}</span>
))}
</div>
</div>
);
}
Здесь определяется структура экземпляра покемона с использованием classname
для стилизации. Будут отображены name
, maxHP
, maxCP
, image
и массив attack
.
Давайте создадим запрос GET_POKEMONS
GraphQL.
📂src/graphql/get-pokemons
GraphQL-запрос
import gql from "graphql-tag";
export const GET_POKEMONS = gql`
query pokemons($first: Int!) {
pokemons(first: $first) {
id
name
image
maxHP
maxCP
attacks {
special {
name
damage
}
}
}
}
`;
Вы импортировали gql
из graphql-tag
и создали запрос GraphQL с именем GET_POKEMONS
.
Функция query pokemons
была заключена в строки, чтобы функция gql
могла анализировать их в документы запроса.
$first: Int!
означает, что ваш запрос ожидает переменную, вызываемую first
, которая является целым числом, а cимвол !
после Int
означает, что переменная обязательна.
Напомним, что мы создали объект variables
в компоненте PokemonsContainer
, он находится здесь ниже.
const { loading, error, data } = useQuery(GET_POKEMONS, {
variables: { first: 5 },
});
pokemons(first: $first)
также был объявлен. Здесь $first
будет присвоено значение 5 (в приведенном выше фрагменте кода мы передали значение 9). Таким образом, массив будет содержать всего 5 объектов. Каждый объект будет содержать id
, name
, image
, maxHP
, maxCP
и объект attacks
, который будет содержать специальный объект, содержащий имя и урон.
Сервер GraphQL может содержать больше свойств, но будет возвращать только свойства, перечисленные выше. Это одна из замечательных функций GraqhQL – она предоставляет вам только те данные, которые вы запрашиваете.
Стилизация нашего приложения
Ваш index.css должен содержать это:
/* RESETS
=========================================== */
html {
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
*,
*:before,
*:after {
-webkit-box-sizing: inherit;
box-sizing: inherit;
}
body {
margin: 20px 0;
padding: 0 20px;
line-height: 1;
font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
color: #202020;
background-color: #fbfbfb;
font-smooth: always;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
/* POKEMON APPLICATION
=========================================== */
.container {
display: flex;
max-width: 80%;
margin: auto;
height: 100vh;
justify-content: space-between;
align-items: center;
gap: 10px;
}
.container p {
margin: 0;
}
.container .pokemon {
width: 20%;
background-color: #fff;
background-clip: border-box;
border: 1px solid rgba(0, 0, 0, 0.125);
border-radius: 0.25rem;
box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
overflow: hidden;
/* margin: 5px; */
}
.container .pokemon__name {
background-color: #ecd018;
text-align: center;
padding: 10px;
}
.container .pokemon__name p {
text-transform: uppercase;
font-weight: bold;
color: white;
letter-spacing: 4px;
text-shadow: 0px 1px 2px rgba(0, 0, 0, 0.4);
}
.container .pokemon__image {
padding: 20px;
min-height: 300px;
display: flex;
align-items: center;
justify-content: center;
}
.container .pokemon__image img {
max-width: 100%;
height: auto;
}
.container .pokemon__attacks {
display: flex;
padding-left: 10px;
padding-right: 10px;
justify-content: space-between;
}
.container .pokemon__attacks span {
width: 32%;
background-color: #f16820;
border-radius: 3px;
padding: 7px;
font-weight: 700;
color: #fff;
padding-left: 10px;
padding-right: 10px;
font-size: 12px;
margin-bottom: 10px;
word-wrap: break-word;
text-align: center;
line-height: 15px;
}
.container .pokemon__meta {
display: flex;
justify-content: space-between;
margin-top: 10px;
padding: 0 10px;
}
.container .pokemon__meta span {
color: white;
text-shadow: 0px 1px 2px rgba(0, 0, 0, 0.4);
background-color: #7bb7b7;
font-weight: bold;
margin: 0;
padding: 5px 20px;
border-radius: 5px;
}
Если все сделано правильно, в вашем браузере должно быть следующее:
Вы можете получить код GitHub: https://github.com/segunajibola/pokemon-graphql
Вы также можете просмотреть действующий сайт, размещенный на Vercel: pokemonsapp.vercel.app
Спасибо за внимание!