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?

【11-2】Next.js app routerのチュートリアルやってみる(URL パラメータを利用したページネーション)

Last updated at Posted at 2024-02-07

はじめに

Next.js app routerのチュートリアルの第11章-2のアウトプットをします。

前の記事

【01】Next.js app routerのチュートリアルやってみる

https://qiita.com/naoyuki2/items/af58da3d20cbc790e767

【02】Next.js app routerのチュートリアルやってみる

https://qiita.com/naoyuki2/items/edf450b3ee135e83d1e8

【03】Next.js app routerのチュートリアルやってみる
https://qiita.com/naoyuki2/items/612221eac233aa9cbb74

【04】Next.js app routerのチュートリアルやってみる

https://qiita.com/naoyuki2/items/62f9beccbfe36eaf7f90

【05】Next.js app routerのチュートリアルやってみる

https://qiita.com/naoyuki2/items/8b71b1d1df7c9435a9c9

【06】Next.js app routerのチュートリアルやってみる

https://qiita.com/naoyuki2/items/58130c3cfbaf8a573de2

【07】Next.js app routerのチュートリアルやってみる

https://qiita.com/naoyuki2/items/2c2da0f8071e60454679

【08】Next.js app routerのチュートリアルやってみる

https://qiita.com/naoyuki2/items/45f45fcb9cc14506f79f

【09】Next.js app routerのチュートリアルやってみる(loading.tsxとSuspenseでストリーミング)

https://qiita.com/naoyuki2/items/717694288ec6017a3af2

【10】Next.js app routerのチュートリアルやってみる(部分的な事前レンダリング)

https://qiita.com/naoyuki2/items/8062f755b0679fe925b1

【11-1】Next.js app routerのチュートリアルやってみる(URLパラメーターを利用した検索機能)

https://qiita.com/naoyuki2/items/2be9503ac80fc4a1fa6a

第11-2章 ページネーション

この章では以下を学びました。

  • ページネーションの実装

第11章の後編です。

ページネーションの追加

前回検索機能を実装できましたが、現在一度に6つまでしかデータを表示できません。

fetchFilterdInvoices関数は一度に6つしかデータを取ってこないからです。

/app/dashboard/invoices/table.tsx
const invoices = await fetchFilteredInvoices(query, currentPage);
/app/lib/data.ts
const ITEMS_PER_PAGE = 6
export async function fetchFilteredInvoices(
    query: string,
    currentPage: number,
) {
    noStore()
    const offset = (currentPage - 1) * ITEMS_PER_PAGE

    try {
        const invoices = await sql<InvoicesTable>`
      SELECT
       // ....
      LIMIT ${ITEMS_PER_PAGE} OFFSET ${offset}
    `

        return invoices.rows
    } catch (error) {
        console.error('Database Error:', error)
        throw new Error('Failed to fetch invoices.')
    }
}

そのため、ページネーションを実装して、すべてのデータを見れるようにしましょう。

前回の検索機能と同じように、URLパラメーターを利用してページネーションを実現します。

合計ページ数を取得

合計ページ数が分からないことにはページネーションは実装できません。

fetchInvoicesPagesという関数をimportします。

そして、この関数にquery(検索キーワード)を渡すことで、合計ページ数が取得できます。

/app/dashboard/invoices/page.tsx
// ...
+import { fetchInvoicesPages } from '@/app/lib/data';
 
export default async function Page({
  searchParams,
}: {
  searchParams?: {
    query?: string,
    page?: string,
  },
}) {
  const query = searchParams?.query || '';
  const currentPage = Number(searchParams?.page) || 1;
+  const totalPages = await fetchInvoicesPages(query);
 
  return (
    // ...
  );
}

そして、合計ページ数totalPages<Pagination />コンポーネントに渡しましょう。

/app/dashboard/invoices/page.tsx
<Pagination totalPages={totalPages} />

<Pagination />コンポーネントに移動しましょう。

そして、フックを利用しURLとパラメータを取得します。

/app/ui/invoices/pagination.tsx
'use client';
 
import { ArrowLeftIcon, ArrowRightIcon } from '@heroicons/react/24/outline';
import clsx from 'clsx';
import Link from 'next/link';
import { generatePagination } from '@/app/lib/utils';
import { usePathname, useSearchParams } from 'next/navigation';
 
export default function Pagination({ totalPages }: { totalPages: number }) {
+ const pathname = usePathname();
+ const searchParams = useSearchParams();
+ const currentPage = Number(searchParams.get('page')) || 1;
 
  // ...
}

そして、次のページや前のページなどのURLが変化する場合にcreatePageURLという関数を呼び出します。

これによって、URLパラメータのpageの部分を変更させています。

'use client';
 
import { ArrowLeftIcon, ArrowRightIcon } from '@heroicons/react/24/outline';
import clsx from 'clsx';
import Link from 'next/link';
import { generatePagination } from '@/app/lib/utils';
import { usePathname, useSearchParams } from 'next/navigation';
 
export default function Pagination({ totalPages }: { totalPages: number }) {
  const pathname = usePathname();
  const searchParams = useSearchParams();
  const currentPage = Number(searchParams.get('page')) || 1;
 
  const createPageURL = (pageNumber: number | string) => {
    const params = new URLSearchParams(searchParams);
    params.set('page', pageNumber.toString());
    return `${pathname}?${params.toString()}`;
  };
 
  // ...
}

そして、前回実装したhandleSearch関数のところに、ページ番号を1にリセットする処理を書きましょう。

/app/ui/search.tsx
'use client';
 
import { MagnifyingGlassIcon } from '@heroicons/react/24/outline';
import { usePathname, useRouter, useSearchParams } from 'next/navigation';
import { useDebouncedCallback } from 'use-debounce';
 
export default function Search({ placeholder }: { placeholder: string }) {
  const searchParams = useSearchParams();
  const { replace } = useRouter();
  const pathname = usePathname();
 
  const handleSearch = useDebouncedCallback((term) => {
    const params = new URLSearchParams(searchParams);
+    params.set('page', '1');
    if (term) {
      params.set('query', term);
    } else {
      params.delete('query');
    }
    replace(`${pathname}?${params.toString()}`);
  }, 300);

おわりに

useStateで管理しなくても実装できるものなんですね。

heroiconがちょくちょく出てくるからいつか調べよう。

次の記事

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?