Reactで綺麗なページネーションを簡単に実装する方法【material-ui】

6 min読了の目安(約5600字TECH技術記事

webアプリを作っていると多くの場面で必要になるのがページネーションです。googleやamazonにも実装されています。


Reactにおいてページネーションを使うにはmaterial-uiが便利なのでこの記事にまとめておきます。

この記事で作成するページネーション

material-uiのページネーションを使う

まずは、material-uiのパッケージの取り込みが必要です。

yarn add @material-ui/lab

通常のmateril-uiのコンポーネントを取り込む際のパッケージと異なるので注意してください。

material-ui/labとは?

material-ui/labとは、まだmaterial-ui/coreに取り込むべきでないライブラリーが入ったものです。

通常、material-uiを使う場合はyarn add @material-ui/coreでcoreを取り込む必要があります。しかし、そのcoreの中にバグが含まれているとバージョンアップするのに時間がかかる。

このような事態に備えて使用頻度が低いものや、コードの質が低いものはlabに分けて登録しているのです。

ページネーションを使う

それでは実際にmaterial-uiのページネーションを使っていきます。

import MuiPagination from '@material-ui/lab/Pagination';
import { withStyles } from '@material-ui/core/styles';
import {useState} from 'react'

export default function Index() {
  //ページ番号
  const [page, setPage] = useState(1)

  const Pagination = withStyles({
    root: {
      display: 'inline-block',  //中央寄せのためインラインブロックに変更
    },
  })(MuiPagination);

  return (
    <div style={{textAlign: "center"}}>
      <Pagination 
        count={10}          //総ページ数
        color="primary"     //ページネーションの色
        onChange={(e, page) =>setPage(page)}  //変更されたときに走る関数。第2引数にページ番号が入る
        page={page}         //現在のページ番号
        />
    </div>
  );
  

}

上記のソースのようにPaginationモジュールを取り込み、必要な属性を設定して使用します。また、クリックされたページ番号をonChangeで変更し、対象の番号をアクティブにしています。

ちなみに、よく使う属性の一覧は以下のようになっています。

  • boundaryCount:最初と最後に表示するページ数
  • count:総ページ数
  • page:現在のページ番号
  • siblingCount:現在のページ前後に表示するページ数

ページャーを中央寄せするには?

ページャーを中央寄せするには、rootである.MuiPagination-rootクラスにdisplay:inline-blockを適用し、親要素にtext-align:centerを追記する必要があります。

ページャーのトップのnav要素はデフォルトだとdisplay:blockが適用されるためtext-align:centerが効きません。そのため、inline-blockに変更してtext-align:centerが効くことで中央寄せが可能になります。

ページネーションのHTML

<nav aria-label="pagination navigation" class="MuiPagination-root WithStyles(ForwardRef(Pagination))-root-20">
  <ul class="MuiPagination-ul">
    <li><button class="MuiButtonBase-root MuiPaginationItem-root MuiPaginationItem-page MuiPaginationItem-textPrimary" tabindex="0" type="button" aria-label="Go to previous page"><svg class="MuiSvgIcon-root MuiPaginationItem-icon" focusable="false" viewBox="0 0 24 24" aria-hidden="true"><path d="M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z"></path></svg><span class="MuiTouchRipple-root"></span></button></li>
    <li><button class="MuiButtonBase-root MuiPaginationItem-root MuiPaginationItem-page MuiPaginationItem-textPrimary" tabindex="0" type="button" aria-label="Go to page 1">1<span class="MuiTouchRipple-root"></span></button></li>
    <li>
      <div class="MuiPaginationItem-root MuiPaginationItem-ellipsis"></div>
    </li>
    <li><button class="MuiButtonBase-root MuiPaginationItem-root MuiPaginationItem-page MuiPaginationItem-textPrimary" tabindex="0" type="button" aria-label="Go to page 5">5<span class="MuiTouchRipple-root"></span></button></li>
    <li><button class="MuiButtonBase-root MuiPaginationItem-root MuiPaginationItem-page MuiPaginationItem-textPrimary Mui-selected" tabindex="0" type="button" aria-current="true" aria-label="page 6">6<span class="MuiTouchRipple-root"></span></button></li>
    <li><button class="MuiButtonBase-root MuiPaginationItem-root MuiPaginationItem-page MuiPaginationItem-textPrimary" tabindex="0" type="button" aria-label="Go to page 7">7<span class="MuiTouchRipple-root"></span></button></li>
    <li>
      <div class="MuiPaginationItem-root MuiPaginationItem-ellipsis"></div>
    </li>
    <li><button class="MuiButtonBase-root MuiPaginationItem-root MuiPaginationItem-page MuiPaginationItem-textPrimary" tabindex="0" type="button" aria-label="Go to page 10">10<span class="MuiTouchRipple-root"></span></button></li>
    <li><button class="MuiButtonBase-root MuiPaginationItem-root MuiPaginationItem-page MuiPaginationItem-textPrimary" tabindex="0" type="button" aria-label="Go to next page"><svg class="MuiSvgIcon-root MuiPaginationItem-icon" focusable="false" viewBox="0 0 24 24" aria-hidden="true"><path d="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z"></path></svg><span class="MuiTouchRipple-root"></span></button></li>
  </ul>
</nav>

ブロック要素のtext-align:center

display:blockは通常、要素が縦方向に並ぶようになっています。しかし、今回の場合は横方向に並んで見えているのはnav配下のulにdisplay: flex;を適用しているためです。これにより横方向に並んでいるように見えます。nav属性自体は縦方向に1行で表示させています。

そのため、以下のようにブロック要素のpタグの親要素にtext-align:center;を追記していも中央寄せになりません。(ただし、pタグ内のテキストは中央寄せされる)

<div style="width: 500px; text-align:center; background-color: blue;">
  <p style="width: 100px; background-color: skyblue;display:block;">
    aaa
  </p>
</div>

インラインブロック要素のtext-align:center

一方、display:inline-blockは横方向に並べる表示方法で、こちらはtext-align:centerによる中央寄せが効きます。ただし、親要素に追記が必要なことは注意が必要です。

<div style="width: 500px; text-align:center; background-color: blue;">
  <p style="width: 100px; background-color: skyblue; display:inline-block;">
    aaa
  </p>
</div>

まとめ

  • material-uiのページネーションを使うには@material-ui/labの取り込みが必要
  • ページ番号をクリックするたびに変更して、アクティブなページを変える
  • material-uiのページネーションはnav要素でできているため、中央寄せするにはrootにdisplay:inline-blockを設定し、親要素にtext-align:center;が必要

参考

material-uiのページネーション