タイトルのとおりですが、最近LaravelとReactでPaginationを作成したので、そのときのメモという形で記事を書きたいと思います。
Laravelでpagination付きのAPIを作成し、ReactではMaterialUIのPaginationを使用して実装してます。
https://mui.com/material-ui/react-pagination/
今回はReact側について記事を書きたい思うので、Laravelに関してはふれておりません…あしからず。
一覧を受け取るカスタムフック
Laravelから受け取るデータの型を定義します。
一覧で表示させたいデータの中身はWord
で、Paginationも含めたものがWordResponseAPI
となります。
export type Word = {
id: number;
user_id: number;
word_en: string;
word_ja: string;
part_of_speech: number;
memory: number;
memo: string;
created_at: string;
updated_at: string;
deleted_at: string | null;
};
export type WordResponseApi = {
current_page: number;
data: Word[];
last_page: number;
total: number;
}
axiosで受け取ります。
上記で宣言した型をimportします。
import axios from "axios";
import { useState } from "react";
import { WordResponseApi } from "../types/word";
export const useAllWords = () => {
const [wordsData, setWordsData] = useState<WordResponseApi>({
current_page: 1,
data: [],
last_page: 1,
total: 0,
});
const fetchPost = async (currentPage: number) => {
try {
const response = await axios.get<WordResponseApi>(`/words?page=${currentPage}`);
setWordsData(response.data);
} catch (error) {
console.log(error);
}
};
return { fetchPost, wordsData };
};
一覧を表示させる
先ほど作成したカスタムフックを使用して、一覧を表示させます。
import React, { useEffect, useState } from "react";
import { useAllWords } from "../hooks/useAllWords";
export const Main = () => {
const getPageNumberFromSession = (): number => {
const pageNumber = sessionStorage.getItem("currentPage");
return pageNumber ? parseInt(pageNumber, 10) : 1;
};
const { fetchPost, wordsData } = useAllWords();
const [page, setPage] = useState(getPageNumberFromSession());
const handleChangePage = (
event: React.ChangeEvent<unknown>,
newPage: number
) => {
setPage(newPage);
fetchPost(newPage);
};
useEffect(() => {
sessionStorage.setItem("currentPage", page.toString());
fetchPost(page);
}, [page]);
return (
<main>
<div className="p-6 bg-white border-b border-gray-200">
<div className="text-gray-600 body-font">
<div className="container mx-auto">
<ul className="flex flex-wrap -m-2">
{wordsData.data.map(
({
id,
word_en,
word_ja,
part_of_speech,
memory,
memo,
created_at,
}) => (
<Word
key={id}
word_id={id}
word_en={word_en}
word_ja={word_ja}
part_of_speech={part_of_speech}
memory={memory}
memo={memo}
created_at={created_at}
onDelete={handleDelete}
onUpdateSuccess={onUpdateSuccess}
/>
)
)}
</ul>
</div>
</div>
<div className="mt-4 flex justify-center">
<Pagination
count={wordsData.last_page}
page={page}
onChange={handleChangePage}
/>
</div>
</div>
</main>
);
};
useState
の初期値にwordsData.currentPage
としてもよかったのですが、
例えば2ページ目以降でリロードしたときに1ページ目に戻ってしまうという問題があったので、
セッションストレージを使用しました。
useEffect
でセッションストレージにつっこみ、getPageNumberFromSession
で取り出すといったイメージです。
以上!