React

 

 

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;

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

about author

PHRASE

Level 60  라이트

오로지 사색하고 검증하기 위해 책을 읽어라. -베이컨

댓글 ( 0)

댓글 남기기

작성