1.페이징 버튼 생성 및 렌더링
페이징 버튼을 만들어 사용자가 페이지 간에 이동할 수 있게 합니다. 여기서는 Pagination 컴포넌트를 사용하여 페이지 버튼을 렌더링합니다.
다음 Pagination 컴포넌트 소스를 가져다 사용하면 된다.
그리고 현재 페이지, 한페지에 표시할 목록수 , 전체 갯수
Pagination.tsx
import Link from "next/link";
import React from "react";
interface PaginationProps {
page: number;
pageSize: number;
totalItems: number;
}
const Pagination: React.FC<PaginationProps> = ({
page,
pageSize,
totalItems,
}) => {
const totalPages = Math.ceil(totalItems / pageSize);
// 페이지 버튼의 범위를 계산합니다
const numButtons = 5; // 보여줄 페이지 버튼의 개수
const startPage = Math.max(1, page - Math.floor(numButtons / 2));
const endPage = Math.min(totalPages, startPage + numButtons - 1);
return (
<section className="container mx-auto flex justify-center items-center my-8">
{page > 1 ? (
<Link href={`/properties?page=${page - 1}`} className="mr-2 px-2 py-1 border border-gray-300 rounded">
이전
</Link>
) : null}
{/* 페이지 번호 버튼을 렌더링합니다 */}
{Array.from({ length: endPage - startPage + 1 }, (_, index) => startPage + index).map((pageNumber) => (
<Link
key={pageNumber}
href={`/properties?page=${pageNumber}`}
className={`mx-1 px-2 py-1 border border-gray-300 rounded ${pageNumber === page ? 'bg-gray-300' : ''}`}
>
{pageNumber}
</Link>
))}
{page < totalPages ? (
<Link href={`/properties?page=${page + 1}`} className="ml-2 px-2 py-1 border border-gray-300 rounded">
다음
</Link>
) : null}
</section>
);
};
export default Pagination;
넥스트의 searchParams 를 이용해서 파라미터 page, pageSize 를 url 받는다.
없을 경우 기본값은 {page=1, pageSize=3} 로 처리 한다.
받아온 파라미터 값을 서버에서 데이터 처리해서 받아오면 된다.
예) PropertiesPage
import { NextPage } from "next";
import PropertyCard from "@/components/properties/PropertyCard";
import { Suspense } from "react";
import LoadingPage from "../loading";
import { propertyList } from "@/actions/mongodb/properties/property/propertyList";
import Pagination from "@/components/common/Pagination";
export interface PropertiesPageProps{
searchParams: {page: number, pageSize: number}
}
const PropertiesPage: NextPage<PropertiesPageProps> =async ({searchParams: {page=1, pageSize=3}} ) => {
const {total , properties}= await propertyList({page, pageSize});
const showPagination = total && total > pageSize;
return (
<section className="px-4 py-6">
<div className="container-xl lg:container m-auto px-4 py-6">
<div className="grid grid-cols-1 md:grid-cols-3 gap-6 text-center">
<Suspense fallback={<LoadingPage loading={true} />}>
{properties && Array.isArray(properties) &&
properties.map((property: any) => (
<PropertyCard key={property._id} property={property} />
))}
</Suspense>
</div>
{!properties || properties.length===0 ? (<p className="grid grid-cols-1 md:grid-cols-1 gap-3 text-center">등록된 게시글이 없습니다.</p>) : null}
{showPagination &&
<Pagination
page={Number(page)}
pageSize={Number(pageSize)}
totalItems={Number(total)}
/>
}
</div>
</section>
);
};
export default PropertiesPage;
리액트
Pagination.tsx
import React from "react";
interface PaginationProps {
currentPage: number;
pageSize: number;
totalItems: number;
onPageChange: (currentPage: number) => void;
}
const Pagination: React.FC<PaginationProps> = ({ currentPage, pageSize, totalItems, onPageChange }) => {
const totalPages = Math.ceil(totalItems / pageSize);
const handlePageClick = (newPage: number) => {
onPageChange(newPage); // 부모에서 상태 관리
};
return (
<section className="container mx-auto flex justify-center items-center my-8">
{currentPage > 1 && (
<button onClick={() => handlePageClick(currentPage - 1)} className="mr-2 px-2 py-1 border border-gray-300 rounded">
이전
</button>
)}
{Array.from({ length: totalPages }, (_, i) => i + 1).map((p) => (
<button
key={p}
onClick={() => handlePageClick(p)}
className={`mx-1 px-2 py-1 border rounded ${p === currentPage ? 'bg-blue-600 border-blue-600 text-white' :
' border-gray-300'}`}
>
{p}
</button>
))}
{currentPage < totalPages && (
<button onClick={() => handlePageClick(currentPage + 1)} className="ml-2 px-2 py-1 border border-gray-300 rounded">
다음
</button>
)}
</section>
);
};
export default Pagination;
TodoListPage 에서 Pagination.tsx사용예 :
import TodoSearchComponent from '@/components/todo/TodoSearchComponent'
import TodosListComponent from '@/components/todo/TodosListComponent'
import React, { useState } from 'react'
import { Link } from 'react-router-dom'
import { useQuery } from '@tanstack/react-query';
import { TodoDTOListRes } from '@/dto/TodoDTO';
import { fetchTodos } from '@/actions/todoAction';
import { queryClient } from '@/utils/queryClient';
import Pagination from '@/components/common/Pagination';
const TodoListPage: React.FC = () => {
const [orderBy, setOrderBy] = useState('id');
const [done, setDone] = useState('all');
const [searchType, setSearchType] = useState('');
const [searchKeyword, setSearchKeyword] = useState('');
const [currentPage, setCurrentPage] = useState(1);
const { data: todos, isLoading, isError, error } = useQuery<TodoDTOListRes, Error>({
queryKey: ['todos', {currentPage, searchType, searchKeyword,orderBy, done }],
queryFn: () => fetchTodos(currentPage, searchType, searchKeyword, orderBy, done),
});
const todoSearch = (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
setCurrentPage(1); // 검색 시 페이지 초기화
queryClient.invalidateQueries({ queryKey: ['todos', {currentPage: 1 , searchType, searchKeyword,orderBy, done}] });
};
const orderByChange = (event: React.ChangeEvent<HTMLSelectElement>) => {
setOrderBy(event.target.value);
queryClient.invalidateQueries({ queryKey: ['todos', {currentPage: 1 , searchType, searchKeyword,orderBy, done}] });
}
const paginationAction = (currentPage: number) => {
setCurrentPage(currentPage);
}
return (
<>
<div className="w-full flex flex-row items-center justify-between">
<h1 className="text-3xl font-bold flex-grow text-center mt-10 mb-10">Todo List!</h1>
<Link to={`/todo/create`} className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">
Todo 생성
</Link>
</div>
<TodoSearchComponent orderByChange={orderByChange} setDone={setDone} todoSearch={todoSearch} setSearchType={setSearchType} setSearchKeyword={setSearchKeyword} />
<TodosListComponent todos={todos?.todos} isLoading={isLoading} isError={isError} error={error} />
<Pagination
currentPage={currentPage}
pageSize={todos?.pageMaker?.pageSize|| 10}
totalItems={todos?.pageMaker?.totalCount || 0}
onPageChange={paginationAction} // 페이지 변경 핸들러
/>
</>
);
};
export default TodoListPage;














댓글 ( 0)
댓글 남기기