react-paginateを使用してページネーション用コンポーネントを作成する

環境

  • windows10
  • DockerDesktop for Win 3.5.x
  • node v14.17.4
  • npm 6.14.14
  • React 17.0.1
  • react-paginate 8.1.0
  • VsCode
  • gitbash 2.32.0.1

動作イメージ

イイ感じですね。サンプルなのでスタイルは最低限にしていますが、結構柔軟に充てれそうです。

設定手順

インストール

npm install react-paginate

ページネーション用コンポーネント

propsの全仕様については、公式を参照ください

react-paginate
A ReactJS component that creates a pagination.

Pagination.jsx

  • react-paginateをimport
  • 親コンポーネントからデータの総数、表示するデータの開始位置、1ページあたりの表示数のpropsを受け取る
  • データの総数を1ページに表示するデータ数で割り、総ページ数を計算する
  • ページクリック時のイベントを定義
    ・選択したページを受け取り、表示するデータが含まれるページの開始位置を更新する
    ・urlを修正する(?page=2)
import ReactPaginate from 'react-paginate'
import React from 'react'
import NumberUtil from '../../shared/function/Number/NumberUtil'

const Pagination = (props) => {
const { dataCounts, setStart, numberOfDisplaysPerpage, currentPage } = props
const totalPageCount = NumberUtil.roundByCeil(dataCounts, numberOfDisplaysPerpage)

// ページクリック時のイベント
const handlePaginate = (selectedPage) => {
  // selectedPage.selectedには、ページ番号 - 1が入る
  const page = selectedPage.selected * numberOfDisplaysPerpage
  setStart(page)
  history.pushState({}, '', `?page=${selectedPage.selected + 1}`)
}

return (
  <ReactPaginate
    forcePage={currentPage} // 現在のページをreactのstateで管理したい場合等
    pageCount={totalPageCount}
    onPageChange={handlePaginate}
    marginPagesDisplayed={4} // 先頭と末尾に表示するページ数
    pageRangeDisplayed={2} // 現在のページの前後をいくつ表示させるか
    containerClassName="pagination justify-center" // ul(pagination本体)
    pageClassName="page-item" // li
    pageLinkClassName="page-link rounded-full" // a
    activeClassName="active" // active.li
    activeLinkClassName="active" // active.li < a
    
    // 戻る・進む関連
    previousClassName="page-item" // li
    nextClassName="page-item" // li
    previousLabel={'<'} // a
    previousLinkClassName="previous-link"
    nextLabel={'>'} // a
    nextLinkClassName="next-link"
   
    // 先頭 or 末尾に行ったときにそれ以上戻れ(進め)なくする
    disabledClassName="disabled-button d-none"
   
    // 中間ページの省略表記関連
    breakLabel="..."
    breakClassName="page-item"
    breakLinkClassName="page-link"
  />
)
}

export default Pagination

pagination.css

.pagination {
    display: flex;
    align-items: center;
    justify-content: center;
    margin-bottom: 10px;
    gap: 20px 6px;
}


.page-item,
.page-link {
    display: inline-flex;
    align-items: center;
    border-radius: 30px;
    justify-content: center;
    font-weight: 700;
    font-size: 16px;
    height: 40px;
    width: 40px;
}

ユーティリティ関数

生成するページ数の計算用

class NumberUtil {

    // 引数の数以上の最小の整数を返します(四捨五入なしの無条件切り上げ)
    static roundByCeil = (numerator, denominator) => {
        return Math.ceil(numerator / denominator)
    }
}

export default NumberUtil

ページネーション表示用コンポーネント

SomethingPage.jsx

  • Pagination.jsxにデータの総数、表示するデータの開始位置、1ページあたりの表示数をpropsでわたす
...割愛
return (
  ...

  // データ表示用コンポーネント
  <Table
    {...{
      start,
      numberOfDisplaysPerpage
    }}
  />  

  // ページネーション
  <BasicContainer className="container-stock__pagination mt-4">
    <Pagination
      dataCounts={stocks.length}
      setStart={setStart}
      numberOfDisplaysPerpage={numberOfDisplaysPerpage}
      currentPage={currentPage}
    />
  </BasicContainer>
...割愛

データ表示用コンポーネント

Table.jsx

  • sliceで選択したページに対応するデータを切り取り、表示する
    slice(全データから切り取る開始位置, そこから取得するデータの数)
return (
  <table class="min-w-full">
    <thead class="bg-black-thin text-whi">
      <THeaderRow headerList={props.headerList} className={'p-10'} />
    </thead>
    <tbody class="bg-black-thin">
      {props.stocks.slice(props.start, props.start + props.numberOfDisplaysPerpage)
      .map((data) => ( 
        <tr>
          <TData
      ...割愛

以上です。

タイトルとURLをコピーしました