2
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.

はじめに

前回記事の続きです。
Step1:API通信
Step2:ポケモンの一覧を取得する
Step3:CardListを作成する
Step4:SearchBarを作成する←今ここ

成果物

search_bar.gif

今回のポイントは検索バーの責務はクエリパラメータを変更する事のみ。
再レンダリングの制御は、クエリパラメータを監視しているコンポーネント側で制御。
これにより、検索バーとコンポーネントの関係を疎結合?にしている。

ソースコード

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

export const Home = () => {
  return (
    <div>
      <h1>ポケモン表示</h1>
      <div>
        <SearchBar />
      </div>
      <PokemonComponent />
    </div>
  );
};
src/features/components/SearchBar.tsx
import React, { useState } from 'react';
import { Button, TextField } from '@mui/material';
import { useNavigate } from 'react-router-dom';

export const SearchBar = () => {
  const [searchTerm, setSearchTerm] = useState('');
  const navigate = useNavigate();

  const handleSearchClick = () => {
    navigate(`?search_id=${encodeURIComponent(searchTerm)}`);
  };

  return (
    <div style={{ marginBottom: '20px' }}>
      <TextField
        label="ポケモン検索"
        variant="outlined"
        value={searchTerm}
        onChange={(e) => setSearchTerm(e.target.value)}
        style={{ marginRight: '10px' }}
      />
      <Button variant="contained" color="primary" onClick={handleSearchClick}>
        検索
      </Button>
    </div>
  );
};
src/features/components/PokemonComponent.tsx
import React from 'react';
import { usePokemon, usePokemons } from '../../api/pokemon/api';
import { isNullish } from '../../common/common';
import { CardList } from './PokemonCardList';
import { useLocation } from 'react-router-dom';

export const PokemonComponent: React.FC = () => {
  const location = useLocation();
  const queryParams = new URLSearchParams(location.search);
  const searchId = queryParams.get('search_id');
  const searchIdNumber = searchId ? parseInt(searchId) : undefined;
  if (searchIdNumber) {
    return <PokemonOne id={searchIdNumber} />;
  }
  return <PokemonList />;
};

export const PokemonList = () => {
  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>
  );
};

type PokemonOneProps = {
  id: number;
};

export const PokemonOne = ({ id }: PokemonOneProps) => {
  const result = usePokemon(id);
  if (result.isLoading || isNullish(result)) {
    return <div>Loading...</div>;
  }
  if (result.isError) {
    return <div>Error: {result.error.message}</div>;
  }
  return (
    <div>
      <h2>Pokemon One</h2>
      <div>{result.data?.name}</div>
      <div>
        {result.data?.sprites.front_default && (
          <img src={result.data?.sprites.front_default} alt="pokemon" />
        )}
      </div>
    </div>
  );
};

今回のポイントは下記。
SearchBarの変更をuseLocationを利用する事で検知している。
useLocationを利用することで、これまでReactHooks等で渡していたset関数等を挟まずにサイレンダリングを実現している。

最後に

ちょっと今回は作ることを優先してコードが雑になってしまいました。
次回以降でリファクタリングを実施していこうと思います!!!

2
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
2
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?