React（Typescript）, Laravel APIでPagination

タイトルのとおりですが、最近LaravelとReactでPaginationを作成したので、そのときのメモという形で記事を書きたいと思います。

Laravelでpagination付きのAPIを作成し、ReactではMaterialUIのPaginationを使用して実装してます。
https://mui.com/material-ui/react-pagination/

今回はReact側について記事を書きたい思うので、Laravelに関してはふれておりません…あしからず。

## 一覧を受け取るカスタムフック

Laravelから受け取るデータの型を定義します。
一覧で表示させたいデータの中身は`Word`で、Paginationも含めたものが`WordResponseAPI`となります。

```javascript:type/word.ts
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します。

```javascript:hooks/useAllWords.ts
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 };
};
```

## 一覧を表示させる

先ほど作成したカスタムフックを使用して、一覧を表示させます。

```react:Main.tsx
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`で取り出すといったイメージです。

以上！