next.js paginationNext js Pagination 구현React pagination next.js pagination ssrfrontend

Next.js와 MongoDB로 손쉽게 구현하는 Pagination

KUKJIN LEE
KUKJIN LEE
2024년 5월 28일
171

※ 이 게시글은 Category가 FrontEnd로 설정되어 있지만, 실제로는 BackEnd 관련 내용도 포함하고 있습니다. FrontEnd 지식만으로는 이해하기 어려울 수 있으므로, 간단한 BackEnd 코드에 대한 이해가 필요합니다.

 

데이터가 많아질수록 모든 데이터를 한 번에 불러오는 것은 비효율적입니다. Pagination(페이징 처리)을 사용하면 사용자 경험을 개선하고 서버 부하를 줄일 수 있습니다. Next.js와 MongoDB를 사용하여 효율적인 Pagination을 구현하는 방법입니다.

 

Pagination 구현을 위한 코드

아래는 Next.js 애플리케이션에서 Pagination을 구현하는 예제입니다. MongoDB에서 데이터를 불러오고, 페이징 처리를 통해 효율적으로 데이터를 관리합니다.

1. 데이터베이스 연결 및 모델 설정 (lib/action)

먼저 데이터베이스와 연결하고, TechUser 모델을 불러옵니다. 그 후, 페이징 처리를 위한 함수를 정의합니다.

  • 데이터베이스 연결: connectToDatabase 함수를 통해 MongoDB에 연결합니다.
  • 모델 불러오기: TechUser 모델을 불러와서 사용합니다.

  • 페이징 처리 함수: getFrontEnd 함수는 검색 조건, 페이지 번호, 페이지당 항목 수, 정렬 기준 등을 받아서 해당 조건에 맞는 데이터를 반환합니다. 또한, 다음 페이지가 있는지 여부도 반환합니다.

 

import { connectToDatabase } from "@/lib/database";
import Tech from "@/models/Tech";
import User from "@/models/User";

export async function getFrontEnd(params) {
  try {
    await connectToDatabase();
    const { searchQuery, page = 1, limit = 10, sort = "-createdAt" } = params;
    const query = { category: "frontend" };
    if (searchQuery) {
      query.$or = [
        { title: { $regex: searchQuery, $options: "i" } },
        { contents: { $regex: searchQuery, $options: "i" } },
      ];
    }
    const totalItems = await Tech.countDocuments(query);
    const frontend = await Tech.find(query)
      .populate({ path: "author", model: User })
      .sort(sort)
      .skip((page - 1) * limit)
      .limit(limit);
    const isNext = page * limit < totalItems;
    return { data: frontend, pageNumber: page, isNext };
  } catch (error) {
    console.error(error);
    throw new Error("Failed to fetch frontend data");
  }
}

 

2. 페이지 컴포넌트 (Page.tsx)

이제 Next.js 페이지 컴포넌트에서 데이터를 불러오고, Pagination 컴포넌트를 사용하여 페이징 처리를 구현합니다.

 

  • 상태 관리: useState 훅을 사용하여 데이터를 저장할 상태와 현재 페이지 번호, 다음 페이지가 있는지를 관리합니다.

  • 라우터 사용: useRouteruseSearchParams 훅을 사용하여 현재 URL의 쿼리 파라미터를 가져오고, 페이지 변경 시 URL을 업데이트합니다.

  • 데이터 불러오기: fetchData 함수를 통해 현재 페이지 번호와 검색 조건에 맞는 데이터를 불러옵니다.

  • 렌더링: FrontEnd 컴포넌트에 데이터를 전달하여 렌더링하고, Pagination 컴포넌트를 사용하여 페이징 버튼을 표시합니다.

 

"use client";
import { useState, useEffect } from "react";
import { useRouter, useSearchParams } from "next/navigation";
import FrontEnd from "./FrontEnd";
import Pagination from "./Pagination";
import { getFrontEnd } from "@/lib/actions/tech.action";

export default function Page() {
  const [result, setResult] = useState({ data: [], pageNumber: 1, isNext: false });
  const router = useRouter();
  const searchParams = useSearchParams();

  const fetchData = async (page = 1) => {
    const params = {
      page,
      limit: 10,
      sort: "-createdAt",
      searchQuery: searchParams.get("search") || ""
    };
    const res = await getFrontEnd(params);
    setResult(res);
  };

  useEffect(() => {
    const page = parseInt(searchParams.get("page")) || 1;
    fetchData(page);
  }, [searchParams]);

  return (
    <>
      <FrontEnd result={result.data} />
      <Pagination pageNumber={result.pageNumber} isNext={result.isNext} />
    </>
  );
}

 

3. Pagination 컴포넌트

Pagination 컴포넌트를 공용 컴포넌트로 작성하여 재사용성을 높입니다.

 

  • 페이지 변경 핸들러: handlePageChange 함수는 새로운 페이지 번호를 받아 URL을 업데이트합니다.

  • 버튼 렌더링: 현재 페이지 번호와 다음 페이지가 있는지를 기준으로 이전 및 다음 버튼을 활성화 또는 비활성화합니다. 현재 페이지 번호를 표시하고, 이전 및 다음 버튼을 클릭할 때 페이지를 변경합니다.

 

import { useRouter } from "next/navigation";

const Pagination = ({ pageNumber, isNext }) => {
  const router = useRouter();
  
  const handlePageChange = (newPage) => {
    router.push(`?page=${newPage}`);
  };

  return (
    <div className="pagination">
      <button 
        onClick={() => handlePageChange(pageNumber - 1)} 
        disabled={pageNumber === 1}
      >
        Previous
      </button>
      <span>{pageNumber}</span>
      <button 
        onClick={() => handlePageChange(pageNumber + 1)} 
        disabled={!isNext}
      >
        Next
      </button>
    </div>
  );
};

export default Pagination;

 

관련 글

TypeScript any 린트 에러(no-explicit-any) 근본적으로 해결하기

TypeScript 프로젝트에서 @typescript-eslint/no-explicit-any 린트 에러는 단순 규칙 비활성화로 해결할 문제가 아닙니다. 눈 앞 문제는 해결할 수 있지만, TypeScript를 사용하는 가장 중요한 이유를 위배하게 됩니다. any 타입은...

2025년 7월 23일269

JSP 주석, 아직도 `` 쓰시나요? 올바른 사용법

코드를 작성하다 보면 주석을 남기는 경우가 많습니다. 하지만 JSP 환경에서 어떤 주석을 사용하냐에 따라 보안 수준과 성능 이 크게 달라집니다. 표준 주석: 서버 사이드 주석 &lt;%-- --%&gt; JSP 페이지 내 개발 관련 주석은 &lt;%-- --%&gt; 를 사용하는게 좋습니다...

2025년 7월 9일144

쉽게 만드는 React Tab 라이브러리 react-tabs

개발자가 커스텀 스타일을 쉽게 적용할 수 있도록 최소한의 스타일만 제공하여 유연한 스타일링 이 가능한 라이브러리입니다. 상태 관리가 내장되어 있어 탭 선택 및 패널 표시 로직을 직접 구현할 필요 없이 간편하게 사용할 수 있습니다. 기본 사용법 먼저, 라이브러리를 설치합...

2025년 6월 17일173

Next.js 환경 변수 NEXT_PUBLIC 접두사 역할

NEXT_PUBLIC 접두사를 붙이면 변수의 접근 범위가 완전히 달라집니다. 이 차이점을 이해하는 것이 안전하고 효율적인 Next.js 애플리케이션을 구축하는 데 중요합니다. NEXT_PUBLIC 접두사가 없는 환경 변수 (서버 전용) NEXT_PUBLIC 접두사 없이...

2025년 6월 13일156