[next.js] Pagination 공통컴포넌트 개발

Yeong·2025년 3월 13일

1. 공통 컴포넌트 생성

import React from "react";
import styles from "../../styles/common/Pagination.module.scss";
import {
  MdOutlineKeyboardArrowLeft,
  MdOutlineKeyboardArrowRight,
  MdOutlineKeyboardDoubleArrowRight,
  MdOutlineKeyboardDoubleArrowLeft,
} from "react-icons/md";

type PaginationProps = {
  totalItems: number; // 전체 데이터 개수
  itemsPerPage: number; // 한 페이지당 표시할 개수
  currentPage: number; // 현재 페이지 번호
  onPageChange: (page: number) => void;
};

const Pagination: React.FC<PaginationProps> = ({
  totalItems,
  itemsPerPage,
  currentPage,
  onPageChange,
}) => {
  const totalPages = Math.ceil(totalItems / itemsPerPage);
  if (totalPages <= 1) return null;

  const pagesPerGroup = 5; // 5개씩 보여줌(1~5, 6~10)
  const currentGroup = Math.ceil(currentPage / pagesPerGroup);
  const startPage = (currentGroup - 1) * pagesPerGroup + 1; // 현재 그룹의 시작 페이지
  const endPage = Math.min(startPage + pagesPerGroup - 1, totalPages); // 현재 그룹의 마지막 페이지

  return (
    <div className={styles.pagination}>
      {/* << 첫 페이지로 이동 */}
      <button disabled={currentPage === 1} onClick={() => onPageChange(1)}>
        <MdOutlineKeyboardDoubleArrowLeft />
      </button>

      {/* < 이전 그룹으로 이동 */}
      <button
        disabled={currentGroup === 1}
        onClick={() => onPageChange(startPage - 1)}>
        <MdOutlineKeyboardArrowLeft />
      </button>

      {/* 현재 그룹의 페이지 번호 표시 */}
      {Array.from({ length: endPage - startPage + 1 }, (_, index) => (
        <button
          key={startPage + index}
          onClick={() => onPageChange(startPage + index)}
          className={currentPage === startPage + index ? styles.active : ""}>
          {startPage + index}
        </button>
      ))}

      {/* > 다음 그룹으로 이동 */}
      <button
        disabled={endPage === totalPages}
        onClick={() => onPageChange(endPage + 1)}>
        <MdOutlineKeyboardArrowRight />
      </button>

      {/* >> 마지막 페이지로 이동 */}
      <button
        disabled={currentPage === totalPages}
        onClick={() => onPageChange(totalPages)}>
        <MdOutlineKeyboardDoubleArrowRight />
      </button>
    </div>
  );
};

export default Pagination;

전체데이터의 개수, 한 페이지당 표시할 개수, 현재 페이지 번호를 부모로 부터 받아온다.

2. api/ board/ route.ts 파일 생성

API Routes를 이용하여 전역적으로 관리할 수 있도록 했다.

import { NextRequest, NextResponse } from "next/server";

const totalCount = 71;
// const totalCount = await fetchFromDB(); // DB에서 동적 데이터 가져오기

export async function GET(_req: NextRequest) {
  void _req; // _req 사용하지 않지만, 사용됨으로 처리

  try {
    // await

    return NextResponse.json({ count: totalCount }, { status: 200 });
  } catch (error) {
    console.error("Error fetching total count:", error);
    return NextResponse.json(
      { error: "Failed to fetch total count" },
      { status: 500 }
    );
  }
}

임시로 값이 필요하여 DB에서 데이터 호출 전 임시 값을 설정했다.

3. 부모 컴포넌트 (ex. boardPagination.tsx)

"use client";

import React, { useEffect, useState } from "react";
import Pagination from "@/components/common/Pagination";

const LawyerPagination = () => {
  const [totalItems, setTotalItems] = useState(0);
  const [currentPage, setCurrentPage] = useState(1);
  const itemsPerPage = 5;

  // API 호출
  useEffect(() => {
    const fetchTotalCount = async () => {
      try {
        const response = await fetch("/api/member");
        
        if (!response.ok) throw new Error("Failed to fetch data");

        const data = await response.json();
        setTotalItems(data.count);
      } catch (error) {
        console.error("Failed to fetch total count", error);
      }
    };
    fetchTotalCount();
  }, []);

  const handlePageChange = (page: number) => {
    setCurrentPage(page);
    console.log(`페이지 변경: ${page}`);
  };
  return (
    <>
      <Pagination
        totalItems={totalItems}
        itemsPerPage={itemsPerPage}
        currentPage={currentPage}
        onPageChange={handlePageChange}
      />
    </>
  );
};

export default LawyerPagination;
  • useState를 이용하여 부모에 전달할 state들을 선언.
  • useEffect를 이용하여 데이터를 받아 선언한 state 에 담기.
    -const response = await fetch("/api/member");
    위 경로가 호출되면, app/api/member/route.ts가 실행되면서, GET 핸들러에서 res 객체가 생성됨.
  • Pagination.tsx 를 import 하여 state 갑을 전달하면 끝 !!

0개의 댓글