반응형
15. AutoComplete 기능 생성하기
검색을 했을때 그에 관련된 검색어를 가져올 수 있게 서버에서 포켓몬 이름을 전달해주면 좋지만 그런 API는 없다. 따라서 이 기능을 구현하려면 프론트엔드에서 먼저 모든 포켓몬의 데이터를 가지고 있어야 한다.
현재는 포켓몬 데이터 limit을 20으로 설정하고있기 때문에 소스 코드의 수정이 필요하다.
refactoring
function App() {
// 모든 포켓몬 데이터를 가지고 있는 State
const [allPokemons, setAllPokemons] = useState([]);
// 실제로 리스트로 보여주는 포켓몬 데이터를 가지고 있는 State
const [displayedPokemons, setDisplayedPokemons] = useState([]);
// 한번에 보여주는 포켓몬 수
const limitNum = 20;
const url = `https://pokeapi.co/api/v2/pokemon/?limit=1008&offset=0`;
const [searchTerm, setSearchTerm] = useState("");
const debouncedSearchTerm = useDebounce(searchTerm, 500);
useEffect(() => {
fetchPokeData();
}, []);
const filterDisplayedPokemonData = (allPokemonsData, displayedPokemons = []) => {
const limit = displayedPokemons.length + limitNum;
// 모든 포켓몬 데이터에서 limitNum만큼 더 가져오기
const array = allPokemonsData.filter((_, index) => index + 1 <= limit); // 20n filter
return array;
}
const fetchPokeData = async () => {
try {
const response = await axios.get(url);
setAllPokemons(response.data.results);
setDisplayedPokemons(filterDisplayedPokemonData(response.data.results));
} catch (error) {
console.error(error)
}
}
return (
...
<section className="pt-6 flex flex-col justify-content items-center overflow-auto z-0">
<div className="flex flex-row flex-wrap gap-[16px] items-center justify-center px-2 max-w-4xl ">
{displayedPokemons.length > 0 ? (
displayedPokemons.map(({ url, name }, index) => (
<PokeCard key={index} url={url} name={name} />
))
) : (
<h2 className="font-medium text-lg text-slate-900 mb-1">
포켓몬이 없습니다.
</h2>
)}
</div>
</section>
{allPokemons.length > displayedPokemons.length &&
displayedPokemons.length !== 1 && (
<div className="text-center">
<button
onClick={() =>
setDisplayedPokemons(
filterDisplayedPokemonData(allPokemons, displayedPokemons)
)
}
className="bg-slate-800 px-6 py-2 my-4 text-base rounded-lg font-bold text-white"
>
더 보기
</button>
</div>
)}
</article>
);
}
16. AutoComplete 컴포넌트 생성하기
AutoComplete.jsx
검색영역 컴포넌트로 가져오기
const AutoComplete = ({ allPokemons, setDisplayedPokemons }) => {
const [searchTerm, setSearchTerm] = useState("");
const debouncedSearchTerm = useDebounce(searchTerm, 500);
const filterNames = (input) => {
const value = input.toLowerCase();
console.log(allPokemons);
return value ? allPokemons.filter((e) => e?.name.includes(value)) : [];
};
const handleSubmit = (e) => {
e.preventDefault();
let text = searchTerm.trim();
setDisplayedPokemons(filterNames(text));
setSearchTerm("");
};
return (
<div className="relative z-50">
<form
onSubmit={handleSubmit}
className="relative flex justify-center items-center w-[20.5rem] h-6 rounded-lg m-auto"
>
<input
type="text"
onChange={(e) => setSearchTerm(e.target.value)}
value={searchTerm}
className="text-xs w-[20.5rem] h-6 px-2 py-1 bg-[hsl(214,13%,47%)] rounded-lg text-gray-300 text-center"
/>
<button
type="submit"
className="text-xs bg-slate-900 text-slate-300 w-[2.5rem] h-6 px-2 py-1 rounded-r-lg text-center absolute right-0 hover:bg-slate-700"
>
검색
</button>
</form>
</div>
);
};
검색시 autocomplete
const checkEqualName = (input) => {
const filteredArray = filterNames(input);
// 검색어 일치하는게 있으면 없애기
return filteredArray[0]?.name === input ? [] : filteredArray; // 배열첫번째거에 이름이 있으면 빈배열
}
UI
{checkEqualName(searchTerm).length > 0 && (
<div
className={`w-full flex bottom-0 h-0 flex-col absolute justify-center items-center translate-y-2`}
>
<div className={`w-0 h-0 bottom-0 border-x-transparent border-x-8 border-b-[8px] border-gray-700 -translate-y-1/2`}>
</div>
<ul
className={`w-40 max-h-[134px] py-1 bg-gray-700 rounded-lg absolute top-0 overflow-auto scrollbar-none`}
>
{checkEqualName(searchTerm).map((e, i) => (
<li key={`button-${i}`}>
<button
onClick={() => setSearchTerm(e.name)}
className={
`text-base w-full hover:bg-gray-600 p-[2px] text-gray-100`
}
>
{e.name}
</button>
</li>
))}
</ul>
</div>
)}
tailwind scrollbar사용하기
설치: npm install -D tailwind-scrollbar
등록: tailwind.config.cjs에서plugins: [require('tailwind-scrollbar')],
추가
반응형
'Frontend > React' 카테고리의 다른 글
[React] 포켓몬도감 만들기5 (1) | 2023.12.08 |
---|---|
[React] 포켓몬도감 만들기4 (0) | 2023.12.08 |
[React] 포켓몬도감 만들기2 (0) | 2023.12.08 |
[React] 포켓몬도감 만들기1 (1) | 2023.12.08 |
[emotion] 이모션을 styled-component처럼 사용하기(@emotion/styled) (0) | 2023.09.05 |