0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Next.js + MUIでページネーション機能の実装

Posted at

はじめに

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コンポーネントや使い方があれば教えてください!

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?