3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Next.js+Material-UIのPaginationでリストを作る

Posted at

#NextでPagination付きのリストを実装したい

サーチエンジンにコンテンツを見て欲しいので、Nextかつインフィニットスクロールではなくてパジネーションを利用してみたかったです。

今回はMaterial-UIのPaginationコンポーネントを利用して、再利用可能なリストを作ってみたのですが、Material-UIやっぱり便利でした。

ページあたりの表示数を動的にするとかなるともう少し複雑になりそうです。

#使用ライブラリー

  • react 17.0.1
  • next 10.0.3
  • @material-ui/lab ^4.0.0-alpha.57
  • react-scroll ^1.8.1 (オプショナル)

#パジネーション付きリストの実装

今回Paginationコンポーネントに渡さないといけないのは以下の3点だけです。

  • currentPage: 現在のページ
  • pageCount: 総ページ数
  • onChange: ページ変更時(ボタンクリック時)のイベント

それに加えて、当然ですがレンダーするアイテムのデータも必要になります。(後から考えたらこれは今回作るコンポーネント内で処理しなくても、childrenとして渡せばいいだけですが...)

なので以下のようなデータをバックエンドから送る前提です。

  • items
  • pageCount

currentPageはnextのrouterから取得します。

##PaginatedList

今回のパジネーション付きリストコンポーネント自体は単純です。リストとパジネーションをレンダーする+onChangeを処理するだけです。

onChangeでは、Paginationがpageを渡してくれるので、それを基にnextでrouter.pushします。

PaginatedList
const PaginatedList: React.FC<PaginatedListProps> = ({
  items,
  pageCount,
  renderItem,
}) => {
  const router = useRouter();
  const currentPage = Number(router.query.page) || 1;

  const handlePageChange = (e: React.ChangeEvent, page: number) => {
    const {pathname, query} = router;
    query.page = `${page}`;
    router.push({
      pathname,
      query,
    });
  };

  return (
    <div>
      {/* このitemsとrenderItemは親からchildrenでlistを渡せばいいだけでした... */}
      {items.map((item) => renderItem(item))}
      <Pagination
        currentPage={currentPage}
        pageCount={pageCount}
        onChange={handlePageChange}
      />
    </div>
  );
};

##nextのページでのgetServerSideProps

上記のonChangeでurlが変わる度に、getServerSidePropsでバックエンドからデータを持ってきます。

getServerSidePropsのcontextからquery.pageにアクセスするだけです。

export const getServerSideProps = async (ctx: NextPageContext) => {
  const data = await fetchListItemsData(ctx.query.page || 1)

  return {props: {data}};
};

##オプショナル:ページ変更時のスクロール

ページ変更時にリストのトップにスクロールさせたかったので、react-scrollを入れてこれも簡単に実装できました。

リスト全体をElementで囲って、onChangeにスクロールの処理を追加するだけです。Elementのnameは念のためオプショナルで渡せるようにしました。

PaginatedList

const PaginatedList: React.FC<PaginatedListProps> = ({
  name = 'paginated-list',
  items,
  pageCount,
  renderItem,
}) => {
  const router = useRouter();
  const currentPage = Number(router.query.page) || 1;

  const handlePageChange = (e: React.ChangeEvent, page: number) => {
    const {pathname, query} = router;
    query.page = `${page}`;
    router.push({
      pathname,
      query,
    });

    //configはお好みに合わせて設定
    scroller.scrollTo(name, {
      duration: 500,
      delay: 50,
      smooth: true,
      offset: -80, 
    });
  };

  return (
    <Element name={name}>
      {items.map((item) => renderItem(item))}
      <Pagination
        currentPage={currentPage}
        pageCount={pageCount}
        onChange={handlePageChange}
      />
    </Element>
  );
};

#まとめ

実質PaginationのonChangeからrouter.pushするだけでした。

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?