페이지 네이션 구현하기

Ji Won·2024년 1월 18일
1

TODAY I LEARNED

목록 보기
14/20
post-thumbnail

진행하고 있는 프로젝트에서 유기견 공고를 받아와서 목록으로 보여주는데 페이지네이션을 사용하기로 했다.
나는 1페이지에 각 15개의 공고를 보여주고자 했고 아래와 같이 구현했다.

const StrayDogs = () => {

  const [selectCity, setSelectCity] = useState('');
  //페이지 번호
  const [page, setPage] = useState(1);
  // 한 페이지에 보여주고자 하는 데이터 수
  const limit = 15;
  const offset = (page - 1) * limit;

  
  // 받아온 유기견 정보 
  const {
    isLoading,
    isError,
    data: strayList
  } = useQuery<StrayList[]>({
    queryKey: ['strayList'],
    queryFn: getStrayList,
    refetchOnWindowFocus: false,
    staleTime: 3000
  }); 


  if (isLoading) {
    return <Loading />;
  }

  if (isError) {
    return <div>🙇🏻‍♀️오류가 발생하였습니다🙇🏻‍♀️</div>;
  }

  // 유기견 공고 목록
  return (
    <div className={style.container}>
      <div className={style.gridContainer}>
        {strayList?.slice(offset, offset + limit).map((list, index) => {
          const formatNoticeEdt = formatDate(list.noticeEdt);
          return (
            <div key={index} className={style.listContainer}>
              <Link href={`/stray-dogs/${list.desertionNo}`}>
                <div className={style.listCard}>
                  <Image
                    src={list.popfile}
                    alt="dog-image"
                    className={style.image}
                    width={250}
                    height={250}
                  />
                  <div className={style.explanationWrap}>
                    <div className={style.titleColumn}>
                      <p>
                        <FaCalendarDays />
                        &nbsp;공고기간
                      </p>
                      <p>
                        <FaDog />
                        &nbsp;견종
                      </p>
                      <p>
                        <PiGenderIntersexFill />
                        &nbsp;성별
                      </p>
                      <p>
                        <FaMapMarkerAlt />
                        &nbsp;발견장소
                      </p>
                    </div>
                    <div className={style.contentColumn}>
                      <p>{formatNoticeEdt} 까지</p>
                      <p>{list.kindCd.slice(3)}</p>
                      <p>{list.sexCd === 'M' ? '수컷' : '암컷'}</p>
                      <p>{list.happenPlace}</p>
                    </div>
                  </div>
                </div>
              </Link>
            </div>
          );
        })}
      </div>

// 페이지네이션 컴포넌트
      <Pagination page={page} setPage={setPage} limit={limit} total={strayList?.length} />
    </div>
  );
};

페이지 번호, 보여주고자 하는 데이터 수를 state로 만들어주고 offset과 같은 식을 만든 후 페이지네이션 컴포넌트에 props로 내려준다.

Pagination.tsx

function Pagination({ page, setPage, total, limit }: Props) {
  const numPages = Math.ceil(total! / limit);
  const pagesToShow = 5;

  const startPage = Math.max(1, page - Math.floor(pagesToShow / 2));
  const endPage = Math.min(numPages, startPage + pagesToShow - 1);

  const renderPageButtons = Array.from(
    { length: endPage - startPage + 1 },
    (_, index) => startPage + index
  );

  return (
    <nav className={style.buttonWrapper}>
      <button
        className={style.button}
        onClick={() => setPage(Math.max(1, page - pagesToShow))}
        disabled={page <= 1}
      >
        &lt;
      </button>
      {renderPageButtons.map((pageNumber) => (
        <button
          key={pageNumber}
          onClick={() => setPage(pageNumber)}
          className={page === pageNumber ? style.selectedPage : style.button}
        >
          {pageNumber}
        </button>
      ))}
      <button
        className={style.button}
        onClick={() => setPage(Math.min(numPages, page + pagesToShow))}
        disabled={page >= numPages}
      >
        &gt;
      </button>
    </nav>
  );
}



profile
1인분 하고 싶은 코린이

0개의 댓글