はじめに
前回記事の続きです。
Step1:API通信
Step2:ポケモンの一覧を取得する
Step3:CardListを作成する
Step4:SearchBarを作成する←今ここ
成果物
今回のポイントは検索バーの責務はクエリパラメータを変更する事のみ。
再レンダリングの制御は、クエリパラメータを監視しているコンポーネント側で制御。
これにより、検索バーとコンポーネントの関係を疎結合?にしている。
ソースコード
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関数等を挟まずにサイレンダリングを実現している。
最後に
ちょっと今回は作ることを優先してコードが雑になってしまいました。
次回以降でリファクタリングを実施していこうと思います!!!
