0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Reactでポケモン図鑑を作成する(Step2:ポケモンの一覧を取得する)

Posted at

はじめに

前回記事の続きです。
Step1:API通信
[Step2:ポケモンの一覧を取得する]←いまここ。

成果物

pokemons.gif

実装

src/components/PokemonComponent.tsx
import React from 'react';
import { usePokemons } from '../api/pokemon/api';
import { isNullish } from '../common/common';

const PokemonComponent: React.FC = () => {
  const { listQuery, detailsQueries } = usePokemons(20, 0);

  if (isNullish(detailsQueries)) return <div>Loading...</div>;
  // 一覧データのローディング中
  if (
    listQuery.isLoading ||
    isNullish(listQuery.data) ||
    isNullish(detailsQueries)
  ) {
    return <div>Loading pokemons...</div>;
  }

  // 一覧データ取得時のエラー
  if (listQuery.isError) {
    return <div>Error: {listQuery.error.message}</div>;
  }

  return (
    <div>
      <h2>Pokemon List</h2>
      <ul>
        {detailsQueries.map((query) => {
          if (query.isLoading || isNullish(query.data)) {
            return <div>Loading...</div>;
          }
          return (
            <li key={query.data?.id}>
              <div>{query.data?.id}</div>
              <div>{query.data?.name}</div>
              <div>
                <img
                  src={query.data.sprites.front_default || ''}
                  alt={query.data.name}
                />
              </div>
            </li>
          );
        })}
      </ul>
    </div>
  );
};

export default PokemonComponent;
src/api/pokemon/api.ts
import { Pokemon } from '@bgoff1/pokeapi-types';
import { UseQueryResult, useQueries, useQuery } from '@tanstack/react-query';
import axios from 'axios';
import { PokemonListResponse, UsePokemonsResult } from './type';

export const getPokemon = async (name: string): Promise<Pokemon> => {
  const response = await axios.get<Pokemon>(
    `https://pokeapi.co/api/v2/pokemon/${name}`
  );
  return response.data;
};

// ポケモンデータを取得するカスタムフック
export const usePokemon = (name: string): UseQueryResult<Pokemon, Error> => {
  return useQuery<Pokemon, Error>({
    queryKey: ['pokemon', name],
    queryFn: () => getPokemon(name),
  });
};

export const getPokemons = async (
  limit = 20,
  offset = 0
): Promise<PokemonListResponse> => {
  const response = await axios.get<PokemonListResponse>(
    `https://pokeapi.co/api/v2/pokemon/?limit=${limit}&offset=${offset}`
  );
  return response.data;
};

export async function getPokemonDetails(url: string): Promise<Pokemon> {
  const { data } = await axios.get(url);
  return data;
}

export const usePokemons = (
  limit: number,
  offset: number
): UsePokemonsResult => {
  const listQuery = useQuery<PokemonListResponse, Error>({
    queryKey: ['pokemonList', limit, offset],
    queryFn: () => getPokemons(limit, offset),
  });

  // useQueriesは常に呼び出されるが、listQuery.dataが存在する場合のみクエリが有効になる
  const detailsQueries = useQueries({
    queries:
      listQuery.data?.results.map((pokemon) => ({
        queryKey: ['pokemonDetails', pokemon.name],
        queryFn: () => getPokemonDetails(pokemon.url),
        enabled: !!listQuery.data, // listQuery.dataが存在する場合のみクエリを有効化
      })) ?? [],
  });

  return { listQuery, detailsQueries };
};

一覧取得時はポケモンの詳細がないため、もう一度APIを叩き直す必要があります。

src/api/pokemon/type.ts
import { Pokemon } from '@bgoff1/pokeapi-types';
import { UseQueryResult } from '@tanstack/react-query';

export interface PokemonListResponse {
  results: Array<{ name: string; url: string }>;
}

export interface UsePokemonsResult {
  listQuery: UseQueryResult<PokemonListResponse, Error>; // 一覧取得のクエリ結果
  detailsQueries: UseQueryResult<Pokemon, Error>[]; // 各ポケモンの詳細情報取得のクエリ結果の配列
}

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?