
nextjs & tailwindでページネーション(Pagination)を実装する方法
公開日:
更新日:
デモ 完成イメージ
本サイトで使用しているPagination機能を紹介します。↓
・記事(Article)を取得して記事数に応じて動的にページ数を組み立てる。
・ページ遷移の矢印ボタンは次の記事(前の記事)の有無によってDisableされる。
・記事データはJson形式で取得する。(データベースは使用しません)
・react-paginateというライブラリを使用しています。
また本サイトではShinさんのチュートリアル動画を参考にページネーションを実装しました。
とても分かりやすいので皆さんも参考にご覧下さい。
ReactとTypescriptでページネーションを実装してみよう【react-paginateを利用】
ディレクトリ構成&環境情報
フォルダ構成は下記の形になります。↓
フォルダ構成図
1/
2└─ src
3 ├─ app
4 │ └─ components
5 │ ├─ article.json
6 │ ├─ Pagination.tsx
7 │ ├─ pagination.css
8 │ ├─ ArticleComponent.tsx
9 │ └─ NewArticleList.tsx
10 └─ lib
11 └─ types.ts
イメージとしては。 NewArticleList.tsx
で全てのコンポーネントを使用する形です。
NewArticleList.tsx
は新着記事一覧を表示するページです。
開発環境は下記です。↓
・言語: typescript
・ライブラリ: React
・フレームワーク: Nextjs (バージョン:15.0.3)
・CSSフレームワーク: tailwind
コード実例
article.json
1
2{
3 "articleList": [
4 {
5 "genre":"記事のジャンル名",
6 "id":2,
7 "url": "記事のURL",
8 "date": "2025/05/14",
9 "description": "記事の説明文",
10 "image":"サムネイル画像のURL"
11 },
12 {
13 "genre":"記事のジャンル名",
14 "id":1,
15 "url": "記事のURL",
16 "date": "2025/05/13",
17 "description": "記事の説明文",
18 "image":"サムネイル画像のURL"
19 },
20 ]
21}
22
23
・ article.json
では記事の情報を持ちます。
・新しいものが上に来るように昇順で記事を格納しています。
・ここにあるデータの総数でページの数も決まります。
Pagination.tsx
1"use client";
2import Article from "@/lib/types";
3import React from "react";
4import ArticleComponent from "./ArticleComponent";
5import { useState } from "react";
6import ReactPaginate from "react-paginate";
7import "./pagination.css";
8import ArrowForwardIcon from "@mui/icons-material/ArrowForward";
9import ArrowBackIcon from "@mui/icons-material/ArrowBack";
10type Props = {
11 articles: Article[];
12};
13function Pagination(props: Props) {
14 const { articles } = props;
15 const itemsPerPage = 6;
16 const [itemsOffset, setItemsOffset] = useState(0);
17 const endOffset = itemsOffset + itemsPerPage;
18 const currentItems = articles.slice(itemsOffset, endOffset);
19 const pageCount = Math.ceil(articles.length / itemsPerPage);
20 const handlePageClick = (event: { selected: number }) => {
21 const newOffset = (event.selected * itemsPerPage) % articles.length;
22 setItemsOffset(newOffset);
23 };
24 return (
25 <div className="">
26 <div className="grid sm:grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-3 mb-3 ">
27 {currentItems.map(
28 (article: {
29 id: number;
30 url: string;
31 date: string;
32 description: string;
33 image: string;
34 genre: string;
35 }) => (
36 <ArticleComponent
37 url={article.url}
38 date={article.date}
39 description={article.description}
40 genre={article.genre}
41 image={article.image}
42 key={article.id}
43 />
44 )
45 )}
46 </div>
47 <div className="w-full flex justify-center pt-10">
48 <ReactPaginate
49 pageCount={pageCount}
50 onPageChange={handlePageClick}
51 marginPagesDisplayed={4} // 先頭と末尾に表示するページ数
52 pageRangeDisplayed={2} // 現在のページの前後をいくつ表示させるか
53 containerClassName="pagination justify-center" // ul(pagination本体)
54 pageClassName="page-item" // li
55 pageLinkClassName="page-link rounded-full" // a
56 activeClassName="active" // active.li
57 activeLinkClassName="active" // active.li < a
58 // 戻る・進む関連
59 previousClassName="page-item" // li
60 nextClassName="page-item" // li
61 previousLabel={<ArrowBackIcon style={{ fontSize: 25, width: 50 }} />}
62 previousLinkClassName="previous-link"
63 nextLabel={<ArrowForwardIcon sx={{ fontSize: 25, width: 50 }} />}
64 nextLinkClassName="next-link"
65 // 先頭 or 末尾に行ったときにそれ以上戻れ(進め)なくする
66 disabledClassName="disabled"
67 // 中間ページの省略表記関連
68 breakLabel="..."
69 breakClassName="page-item"
70 breakLinkClassName="page-link"
71 />
72 </div>
73 </div>
74 );
75}
76
77export default Pagination;
78
・ Pagination.tsx
が今回のメインです。
・こちらに関してはShinさんのチュートリアル動画で詳しく解説されています。
・見た目を調整するためpagination.css
で定義したクラス名が何箇所か出てきています。
・レスポンシブ対応済でスマホでは記事が1列、PCだと2列、モニターなど大きな画面では3列に記事が並びます。
pagination.css
1.pagination {
2 display: flex;
3 align-items: center;
4 justify-content: center;
5 margin-bottom: 10px;
6 gap: 20px 6px;
7}
8
9.active{
10background-color:#798777 ;
11}
12
13.disabled{
14 color: #a9a9a9;
15}
16.page-item,
17.page-link {
18 display: inline-flex;
19 align-items: center;
20 border-radius: 30px;
21 justify-content: center;
22 font-weight: 700;
23 font-size: 16px;
24 height: 40px;
25 width: 40px;
26}
・Pagination.tsx
の見た目を調整するCSSファイルです。
・Pagination.tsx
と同階層に設置しています。
ArticleComponent.tsx
1import Link from "next/link";
2import React from "react";
3import Image from "next/image";
4
5export type ClassName = {
6 className: string;
7};
8
9type ArticleProps = {
10 url: string;
11 date: string;
12 description: string;
13 image: string;
14 genre: string;
15};
16
17const ArticleComponent = ({ url, description, date, image }: ArticleProps) => {
18 return (
19 <>
20 <Link
21 href={url}
22 className=" hover:opacity-75 hover:scale-105 duration-300 hover:shadow-lg hover:shadow-gray-400 "
23 >
24 <article className="shadow bg-white rounded h-96">
25 <div className="items-center flex justify-center pt-3">
26 <Image
27 src={image}
28 height={180}
29 width={342}
30 alt="アイキャッチの画像"
31 />
32 </div>
33 <div className=" flex items-center ">
34 <div className="p-3 flex flex-col ">
35 <p className="text-sm mb-1 text-slate-400 ">投稿日 {date}</p>
36 <p className="md:text-sm lg:text-lg font-semibold pb-2">
37 {description}
38 </p>
39 </div>
40 </div>
41 </article>
42 </Link>
43 </>
44 );
45};
46
47export default ArticleComponent;
48
・article.json
の記事をカード化して見た目を調整しているクラスです。
・hoverしたらスケールアップして大きくなったりとアニメーションを定義しています。
NewArticleList.tsx
1import { promises as fs } from "fs";
2import Pagination from "../components/Pagination";
3
4export default async function Page() {
5 const file = await fs.readFile(
6 process.cwd() + "/src/app/components/article.json",
7 "utf8"
8 );
9 const data = JSON.parse(file);
10
11 return (
12 <>
13 <div className="mb-3 w-full">
14 <h1 className="text-lg font-bold">新着記事</h1>
15 </div>
16 <div className=" w-full">
17 <div>
18 <div className="flex flex-row justify-between">
19 <Pagination articles={data.articleList} />
20 </div>
21 </div>
22 </div>
23 </>
24 );
25}
26
・ここではまず fs.readFile
の部分でarticle.json
より全ての記事を受け取っています。
・記事を受けとったらJSON.parse
の部分でJsonをパースしてPagination
コンポーネントに読み込んだ記事を渡して完成です。
まとめ
上記で紹介しているコンポーネントでページネーション機能を実現できます。

本記事は以上になります。
ご一読頂きありがとうございました。
目次