7-2-1. Species API

src/hooks/useSpecies.ts

/src 디렉토리 하위에 /hooks 를 생성하고, 그 하위에 포켓몬 종(species) 정보를 가져오는 커스텀 훅(/useSpecies.ts)을 추가합니다.

import axios, { AxiosResponse } from 'axios';
import { useQuery } from 'react-query';

import { SpeciesResponse } from '../types';

const speciesApi = (id: string) => axios.get(`https://pokeapi.co/api/v2/pokemon-species/${id}`)

const useSpecies = (id: string) =>
  useQuery<AxiosResponse<SpeciesResponse>, Error>(['species', { id }], () => speciesApi(id));

export default useSpecies;

아래와 같이 사용할 수 있습니다.

const speciesQueryResult = useSpeciesQuery(id);

미리 만들어 둔 src/pages/DetailPage.tsx 컴포넌트에 적용해보겠습니다.

import React, { useMemo, useState } from 'react';
import { useParams } from 'react-router-dom';
import styled from '@emotion/styled/macro';

import PokemonInfo from '../components/PokemonInfo';
import Tabs from '../components/Tabs';
import About from '../components/About';
import Stats from '../components/Stats';
import Evolution from '../components/Evolution';

import { PokemonResponse } from '../types';
import usePokemonQuery from '../hooks/usePokemonQuery';
import useSpeciesQuery from '../hooks/useSpecies';

type Params = {
  id: string;
}

type Tab  = 'about' | 'stats' | 'evolution';

const Container = styled.section`
  display: flex;
  flex-direction: column;
`;

const TabsWrapper = styled.div`
  margin: 24px auto 0;
`;

const DetailPage: React.FC = () => {
  const { id } = useParams<Params>();

  const [selectedTab, setSelectedTab] = useState<Tab>('about');

  const speciesQueryResult = useSpeciesQuery(id);

  const {
    color,
    growthRate,
    flavorText,
    genderRate,
    isLegendary,
    isMythical,
    evolutionChainUrl,
  } = useMemo(() => ({
    color: speciesQueryResult.data?.data.color,
    growthRate: speciesQueryResult.data?.data.growth_rate.name,
    flavorText: speciesQueryResult.data?.data.flavor_text_entries[0].flavor_text,
    genderRate: speciesQueryResult.data?.data.gender_rate,
    isLegendary: speciesQueryResult.data?.data.is_legendary,
    isMythical: speciesQueryResult.data?.data.is_mythical,
    evolutionChainUrl: speciesQueryResult.data?.data.evolution_chain.url,
  }), [speciesQueryResult]);

  const handleTabClick = (tab: Tab) => {
    setSelectedTab(tab);
  };

  return (
    <Container>
      <PokemonInfo
        id={id}
        name={name}
        types={types}
        color={color}
      />
      <TabsWrapper>
        <Tabs
          color={color}
          tab={selectedTab}
          onClick={handleTabClick}
        />
      </TabsWrapper>
      {
        selectedTab === 'about' && (
          <About
            isLoading={pokemonQueryResult.isLoading || speciesQueryResult.isLoading} 
            color={color} 
            growthRate={growthRate}
            flavorText={flavorText}
            genderRate={genderRate}
            isLegendary={isLegendary}
            isMythical={isMythical}
            types={types}
            weight={weight}
            height={height}
            baseExp={baseExp}
            abilities={abilities}
          />
        )
      }
      {
        selectedTab === 'stats' && (
          <Stats
           isLoading={pokemonQueryResult.isLoading || speciesQueryResult.isLoading}
           color={color}
           stats={stats}
          />
        )
      }
      {
        selectedTab === 'evolution' && (
          <Evolution
            id={id}
            isLoading={speciesQueryResult.isLoading}
            color={color}
            url={evolutionChainUrl}
          />
        )
      }
    </Container>
  )
}

export default DetailPage;

각 탭에 해당하는 컴포넌트를 작성해주겠습니다.

먼저 해당 포켓몬의 간단한 정보를 보여주는 <About /> 컴포넌트

포켓몬의 스탯 정보를 나타낼 <Stats /> 컴포넌트

  • About

  • Stats

참고 : https://github.com/fastcampus-react-playground/pokedex/tree/master/srcarrow-up-right

Last updated