Next.js × microCMS におけるページングの実装方法

Next.js × microCMS におけるページングの実装方法

Next.jsmicroCMSTypeScriptMaterial-UI

おはこんにちばんは。今回は Next.js × microCMS で ページングを実装してみました。その手順を紹介しようと思います!

実行環境

  • Next.js 10.0.4
  • React 17.0.0
  • Material-UI 4.11.2

一覧画面の実装

まずは雑に一覧画面を実装します。今回はUIライブラリにMaterial-UIを利用しています。構成しては以下になります。

=============

pages/

 page/

  [offset].tsx

=============

src/pages/page/[offset].tsx
1import { GetStaticPaths, GetStaticProps, NextPage } from 'next'
2import React, { useCallback } from 'react'
3import { useRouter } from 'next/router';
4import { Pagination } from '@material-ui/lab';
5
6const PAGE = 10 as const;
7
8const DynamicPage: NextPage = () => {
9 const router = useRouter();
10 const offset = router.query.offset
11 ? Number.parseInt(String(router.query.offset), 10)
12 : 1;
13
14 const handleChangePage = useCallback(
15 (_: React.ChangeEvent<unknown>, page: number) => {
16 void router.push(`/page/${page}`);
17 },
18 [router],
19 );
20
21 return (
22 <div>
23 <h1>{router.query.offset}</h1>
24 <Pagination
25 count={PAGE}
26 variant="outlined"
27 shape="rounded"
28 color="secondary"
29 page={offset}
30 onChange={handleChangePage}
31 />
32 </div>
33 )
34}
35
36export const getStaticPaths: GetStaticPaths = async () => {
37 const paths = [...Array(PAGE)].map((_, index) => ({
38 params: {
39 offset: `${index + 1}`,
40 },
41 }))
42
43 return { paths, fallback: false };
44}
45
46export const getStaticProps: GetStaticProps = async (context) => {
47 return {
48 props: {},
49 }
50}
51
52export default DynamicPage;

Material-UI の Pagination を使っています。ハンドラーの第二引数に次の page が取れるのでそれを元に次のページに遷移させています。こんな感じになるはずです。

blog image

microCMS で取得したコンテンツを利用

microCMS で取得したコンテンツを元にページングしていきます。今回は1ページ 3つまでコンテンツを取得するようにしています。

1import { GetStaticPaths, GetStaticProps, NextPage } from 'next'
2import React, { useCallback } from 'react'
3import { useRouter } from 'next/router';
4import { Pagination } from '@material-ui/lab';
5
6const DynamicPage: NextPage = ({ contents }) => {
7 const router = useRouter();
8 const offset = router.query.offset
9 ? Number.parseInt(String(router.query.offset), 10)
10 : 1;
11
12 const handleChangePage = useCallback(
13 (_: React.ChangeEvent<unknown>, page: number) => {
14 void router.push(`/page/${page}`);
15 },
16 [router],
17 );
18
19 return (
20 <div>
21 <h1>{router.query.offset}</h1>
22 <Pagination
23 count={Math.ceil(contents.totalCount / contents.limit)}
24 variant="outlined"
25 shape="rounded"
26 color="secondary"
27 page={offset}
28 onChange={handleChangePage}
29 />
30 </div>
31 )
32}
33
34export const getStaticPaths: GetStaticPaths = async () => {
35
36 const key = {
37 headers: { 'X-API-KEY': process.env.API_KEY ?? '' },
38 };
39 const contents = await fetch(
40 `https://jun-dev.microcms.io/api/v1/contents?offset=0&limit=3`,
41 key,
42 )
43 .then((res) => res.json())
44 .catch(() => null);
45
46 const paths = [...Array(Math.ceil(contents.totalCount / contents.limit))]
47 .map((_, i) => i + 1)
48 .map((offset) => `/page/${offset}`);
49
50 return { paths, fallback: false };
51}
52
53export const getStaticProps: GetStaticProps = async ({ params }) => {
54 const offset = params?.offset ? String(params?.offset) : '0';
55
56 const query = {
57 offset: String(Math.ceil(Number.parseInt(offset, 10) - 1) * 3),
58 limit: '3',
59 };
60
61 const key = {
62 headers: { 'X-API-KEY': process.env.API_KEY ?? '' },
63 };
64 const contents = await fetch(
65 `https://your-service.microcms.io/api/v1/contents?offset=${query.offset}&limit=${query.limit}`,
66 key,
67 )
68 .then((res) => res.json())
69 .catch(() => null);
70
71 return {
72 props: {
73 contents
74 },
75 }
76}
77
78export default DynamicPage
79

getStaticPathsでは microCMS で totalCountlimit を返してくれるのでこれを元にpathsを生成しています。

1 const paths = [...Array(Math.ceil(contents.totalCount / contents.limit))]
2 .map((_, i) => i + 1)
3 .map((offset) => `/page/${offset}`);
4

getStaticPropsではgetStaticPathsで生成したoffsetを元にqueryを生成し、ページ単位でコンテンツを何件目から取得するかを指定しています。

1 const offset = params?.offset ? String(params?.offset) : '0';
2
3 const query = {
4 offset: String(Math.ceil(Number.parseInt(offset, 10) - 1) * 3),
5 limit: '3',
6 };

Pagination コンポーネントも totalCountlimit を元にcount(何ページ目か) を指定してあげています。

1<Pagination
2 count={Math.ceil(contents.totalCount / contents.limit)}
3 variant="outlined"
4 shape="rounded"
5 color="secondary"
6 page={offset}
7 onChange={handleChangePage}
8/>

これで以上です。お疲れ様でした。

さいごに

Next.js × microCMS で ページングを実装してみました。一覧ページを実装したけど、ページングがよくわからんって方に参考となれば幸いです。