PokeAPI는 총 1302개의 포켓몬 데이터를 제공합니다.
하지만 1302개의 데이터를 한 번에 보여주는 것은 비효율적이여서 이를 해결하기 위해 페이지네이션 기능을 구현했습니다.
PokeAPI 데이터 가져오기
PokeAPI는 전체 포켓몬의 개수를 count로 제공합니다. 이를 활용해 데이터를 20개씩 나눠서 가져오도록 했습니다.
export async function fetchPokemon(page = 1): Promise<{ count: number; results: Pokemon[] }> {
const offset = (page - 1) * 20;
const response = await fetch(`${pokemonBaseUrl}/pokemon?limit=20&offset=${offset}`);
if (!response.ok) {
throw new Error('포켓몬 목록을 가져오는 데 실패했습니다.');
}
const data = await response.json();
return { count: data.count, results: data.results };
}
- limit: 한 페이지에 표시할 포켓몬의 수 (여기서는 20으로 설정)
- offset: 페이지 번호에 따라 가져올 데이터의 시작점. (page - 1) * limit으로 계산
maxVisiblePages
페이지네이션에서 한 번에 보여질 페이지 번호의 최대 개수를 제한하기 위해 maxVisiblePages를 선언했습니다. 여기서는 5로 설정했습니다.
const maxVisiblePages = 5;
getPageNumbers 함수
getPageNumbers 함수는 페이지네이션 번호와 생략 기호(...)를 생성합니다.
이 함수는 최대 maxVisiblePages개의 페이지 번호를 표시하고, 필요하면 생략 기호를 포함합니다.
const getPageNumbers = () => {
const pages: (number | '...')[] = [];
pages.push(1);
if (currentPage < maxVisiblePages) {
for (let i = 2; i <= Math.min(totalPages - 1, maxVisiblePages); i++) {
pages.push(i);
}
} else {
const half = Math.floor((maxVisiblePages - 1) / 2);
const startPage = Math.max(2, currentPage - half);
const endPage = Math.min(totalPages - 1, currentPage + half);
if (startPage > 2) {
pages.push('...');
}
for (let i = startPage; i <= endPage; i++) {
pages.push(i);
}
}
if (currentPage + Math.floor((maxVisiblePages - 1) / 2) < totalPages - 1) {
pages.push('...');
}
pages.push(totalPages);
return pages;
};
- maxVisiblePages로 한 번에 보여질 최대 페이지 번호를 제한.
- 첫 번째 페이지 번호(1)는 항상 추가.
- currentPage가 maxVisiblePages보다 작으면 순차적으로 번호를 추가.
- currentPage가 중앙에 위치하도록 앞뒤로 균형 있게 페이지 번호를 추가.
- 필요한 경우 생략 기호(...)를 삽입.
- 마지막 페이지 번호(totalPages)를 추가.
전체 코드
'use client';
import Link from 'next/link';
type Props = {
currentPage: number;
totalPages: number;
};
export default function Pagination({ currentPage, totalPages }: Props) {
const maxVisiblePages = 5;
const getPageNumbers = () => {
const pages: (number | '...')[] = [];
pages.push(1);
if (currentPage < maxVisiblePages) {
for (let i = 2; i <= Math.min(totalPages - 1, maxVisiblePages); i++) {
pages.push(i);
}
} else {
const half = Math.floor((maxVisiblePages - 1) / 2);
const startPage = Math.max(2, currentPage - half);
const endPage = Math.min(totalPages - 1, currentPage + half);
if (startPage > 2) {
pages.push('...');
}
for (let i = startPage; i <= endPage; i++) {
pages.push(i);
}
}
if (currentPage + Math.floor((maxVisiblePages - 1) / 2) < totalPages - 1) {
pages.push('...');
}
pages.push(totalPages);
return pages;
};
const pageNumbers = getPageNumbers();
return (
<div className="mb-10 flex justify-center items-center gap-2">
{pageNumbers.map((page, index) => {
if (page === '...') {
return (
<span key={`ellipsis-${index}`} className="text-gray-500 px-2">
...
</span>
);
}
return (
<Link
key={page}
href={`/?page=${page}`}
className={`py-2 px-4 w-10 h-10 flex items-center justify-center rounded-full ${
page === currentPage
? 'bg-purple text-white font-bold'
: 'bg-gray-200 text-black hover:bg-purple/30'
}`}
>
{page}
</Link>
);
})}
</div>
);
}
'Next.js > Pokemon' 카테고리의 다른 글
Zustand로 상태 관리, 포켓몬 검색 기능 구현하기 (0) | 2025.01.02 |
---|---|
MongoDB와 Prisma를 활용한 북마크/좋아요 기능 구현 (0) | 2025.01.01 |
Next.js 15.1.2 -> 14.2.21로 다운그레이드 (0) | 2024.12.27 |
Next.js와 Auth0를 이용한 간단한 로그인 기능 구현하기 (0) | 2024.12.23 |