Reactでポケモン図鑑を作成する(Step3:CardListを作成する)

## はじめに
前回記事の続きです。
[Step1:API通信](https://qiita.com/koji0705/items/fc7569af1d81e5607339)
[Step2:ポケモンの一覧を取得する](https://qiita.com/koji0705/items/5a8e85af4167bea0f8d4)
Step3:CardListを作成する←いまここ。

## 成果物

![card_list.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599049/256b9b37-c6bf-9a49-30f6-6cb4e6ce8093.gif)

https://github.com/kouji0705/react_pokemon/pull/3

## ソースコード
```tsx:src/index.tsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { ThemeProvider, createTheme } from '@mui/material';

// QueryClient インスタンスの作成
const queryClient = new QueryClient();

const root = ReactDOM.createRoot(
  document.getElementById('root') as HTMLElement
);

const theme = createTheme({
  palette: {
    primary: {
      main: '#556cd6',
    },
    secondary: {
      main: '#19857b',
    },
  },
});

root.render(
  <React.StrictMode>
    <ThemeProvider theme={theme}>
      <QueryClientProvider client={queryClient}>
        <App />
      </QueryClientProvider>
    </ThemeProvider>
  </React.StrictMode>
);

```
:::note info
今回からmuiを利用。そのため、Providerの設定をしています。
:::

```tsx:src/App.tsx
import React from 'react';
import { Home } from './pages/Home';

function App() {
  return <Home />;
}

export default App;
```

```src/pages/Home.tsx
import { PokemonComponent } from '../components/PokemonComponent';

export const Home = () => {
  return (
    <div>
      <h1>ポケモン表示</h1>
      <PokemonComponent />
    </div>
  );
};
```
:::note info
Pageとコンポーネントを分けたいため、Page表示用のコンポーネントを作成しています。
:::

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

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

  if (isNullish(detailsQueries)) return <div>Loading...</div>;
  console.log('listQuery', listQuery);
  console.log('HIT8 detailsQueries', detailsQueries);
  // 一覧データのローディング中
  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>
      <CardList detailsQueries={detailsQueries} />
    </div>
  );
};

```

```tsx:src/components/PokemonCardList.tsx
import React from 'react';
import { UseQueryResult } from '@tanstack/react-query';
import { Card } from './Card';
import { Pokemon } from '@bgoff1/pokeapi-types';
import { Grid } from '@mui/material';

interface CardListProps {
  detailsQueries: UseQueryResult<Pokemon, Error>[];
}

export const CardList: React.FC<CardListProps> = ({ detailsQueries }) => {
  return (
    <Grid container spacing={2}>
      {detailsQueries.map((query, index) => (
        <Grid item xs={12} sm={6} md={4} key={index}>
          {query.isLoading || !query.data ? (
            <div>Loading...</div>
          ) : (
            <Card
              id={query.data.id}
              name={query.data.name}
              image={query.data.sprites.front_default ?? ''}
            />
          )}
        </Grid>
      ))}
    </Grid>
  );
};

```

```tsx:src/components/Card.tsx
interface CardProps {
  id: number;
  name: string;
  image: string;
}

export const Card: React.FC<CardProps> = ({ id, name, image }) => {
  return (
    <div className="card">
      <div className="card-id">#{id}</div>
      <div className="card-name">{name}</div>
      <div className="card-image">
        <img src={image} alt={name} />
      </div>
    </div>
  );
};

```