はじめに
Next.jsとsupabaseを用いた記事投稿一覧ページを作成の中で、ページネーション機能を実装したくなったので、まとめました。
主にMUI(Material UI)の公式ドキュメントを元に作成しています。
公式ドキュメント
動作環境
・next: "^14.2.5"
・@mui/base: "^5.0.0-beta.40"
・@mui/material: "^6.0.0"
・@mui/material-nextjs: "^6.0.0"
・tailwindcss: "^3.4.1"
・@supabase/ssr: "^0.4.0"
・@supabase/supabase-js: "^2.45.1"
本題
今回はページネーション機能がメインのため、db等の説明は省きます。
"use client";
import { createClient } from "@/utils/supabase/client";
import { Pagination, PaginationItem } from "@mui/material";
import { redirect, useRouter, useSearchParams } from "next/navigation";
import { useEffect, useState } from "react";
import Link from "next/link";
const ITEMS_PER_PAGE = 20; //1ページあたりの記事の表示数
export default function Articles() {
const supabase = createClient();
const searchParams = useSearchParams(); // クエリパラメータを取得
const page = parseInt(searchParams.get('page') || '1', 10);
const [totalCount, setTotalCount] = useState(0);
useEffect(() => {
const fetchArticles = async () => {
const start = (page - 1) * ITEMS_PER_PAGE;
const end = start + ITEMS_PER_PAGE - 1;
// 合計記事数を取得
const { count: totalArticlesCount } = await supabase
.from('articles')
.select('*', { count: 'exact', head: true });
setTotalCount(totalArticlesCount || 0);
// 記事データを取得
const { data: articlesData, error } = await supabase
.from('articles')
.select(`
article_id, title, updated_at,
users (
username, avatar_url
)
`)
.limit(limit)
.range(start, end)
.order('updated_at', { ascending: false });
fetchArticles();
}, [page, limit, router, supabase]);
const handlePageChange = (event: React.ChangeEvent<unknown>, value: number) => {
router.push(`/articles?page=${value}`); // ページ変更時にクエリパラメータを更新
};
return (
{articles.map((article) => (
<Link href={`/articles/${article.article_id}`} key={id}>
<div>{article.title}</div>
<div>{article.updated_at}</div>
</Link>
)}
<Pagination
page={page}
count={Math.ceil(totalCount / ITEMS_PER_PAGE)}
onChange={handlePageChange}
renderItem={(item) => (
<PaginationItem
component={Link}
href={`/articles${item.page === 1 ? '' : `?page=${item.page}`}`}
{...item}
/>
)}
/>
)}
ちょこっと解説
・dbから記事総数を取得し、1ページに表示したい数で割ってあげることでページネーションのMax値を動的に設定
・後はほとんど公式通りの実装でいける
終わりに
MUIやshadcn,chakraUIなど色々触ってみたが、どのUIライブラリも同じような感覚でした。
デザインが綺麗なのでデフォルトでもいいのがとても助かります。
ぜひおすすめのUIコンポーネントや使い方があれば教えてください!