この記事ではSWRのuseSWRInfinite()
を使って「もっと見る」機能の実装方法をサンプルコードを使ってご紹介します。
サンプルコードのデモは次の通りです。
このデモの仕様は
- 1ページ目から取得
- 1ページあたり2枚の写真
- ボタンをクリックすると次のページの写真を取得
- 新しく取得した写真は追加して表示する
です。
このサンプルコードの紹介と解説をします。
SWRを使った「もっと見る」機能のサンプルコード
以下がサンプルコードです。
「もっと見る」機能を実装するためだけの最小構成にしています。
import "./styles.css";
import useSWRInfinite from "swr/infinite";
import axios from "axios";
export default function App() {
const limit = 2;
const getKey = (pageIndex, previousPageData) => {
if (previousPageData && !previousPageData.length) return null;
return `https://picsum.photos/v2/list?page=${pageIndex + 1}&limit=${limit}`; // SWR key
};
const {
data: picList,
error,
isValidating,
mutate,
size,
setSize
} = useSWRInfinite(getKey, (url) => fetch(url).then((r) => r.json()), {
initialSize: 2
});
// axios を使用してデータを取得
// const {
// data: picList,
// error,
// isValidating,
// mutate,
// size,
// setSize
// } = useSWRInfinite(getKey, (url) => axios.get(url).then((res) => res.data), {
// initialSize: 2
// });
const isEmpty = picList?.[0]?.length === 0;
const isReachingEnd =
isEmpty || (picList && picList[picList.length - 1]?.length < limit);
if (error) return "failed to load";
if (!picList) return "loading";
const pics = picList.flat();
return (
<div className="App">
<h2>SWRを使った「もっと見る」機能</h2>
{pics.map((pic, i) => (
<div key={i} style={{ width: "40%" }}>
<img
src={pic.download_url}
style={{ width: "100%" }}
alt={pic.author}
/>
</div>
))}
{!isReachingEnd ? (
<button onClick={() => setSize(size + 1)}>もっと見る</button>
) : (
"すべて読み込みました。"
)}
</div>
);
}
サンプルコードの解説
今回のサンプルコードでキモになるのがSWRのuseSWRInfinite()です。
useSWRInfinite()を使うことでシンプルに「もっと見る」機能を実装しています。
このサンプルコードのポイントになるのは以下の点です。
- useSWRInfinite()を使ってデータを取得
- useSWRInfinite()で取得したデータを整形
- 次のページのデータを取得
- 最後のページのデータであることを検知する
これらについて詳しく説明します。
useSWRInfinite()を使ってデータを取得
基本的なuseSWRInfinite()の使い方は次のとおりです。
import useSWRInfinite from 'swr/infinite'
// ...
const { data, error, isValidating, mutate, size, setSize } = useSWRInfinite(
getKey, fetcher?, options?
)
この関数をサンプルコード内では以下のように使用しました。
import useSWRInfinite from "swr/infinite";
...
const getKey = (pageIndex, previousPageData) => {
if (previousPageData && !previousPageData.length) return null;
return `https://picsum.photos/v2/list?page=${pageIndex + 1}&limit=2`;
};
const {
data: picList,
error,
isValidating,
mutate,
size,
setSize
} = useSWRInfinite(getKey, (url) => fetch(url).then((r) => r.json()), {
initialSize: 2
});
...
useSWR()とは違い第一引数にはkeyとなるパラメータ付きのURLを返す関数を入れています。
オプションのinitialSizeでははじめに2ページ分のデータを取得するように設定しています。
useSWRInfinite()
を使った無限スクロールも簡単に作れます。
useSWRInfinite()で取得したデータを整形
useSWRInfinite()で取得したデータは以下の構成になっています。
[
// 1ページ目
[
{
id: "0"
author: "Alejandro Escamilla"
width: 5616
height: 3744
url: "https://unsplash.com/photos/yC-Yzbqy7PY"
download_url: "https://picsum.photos/id/0/5616/3744"
},
...
],
// 2ページ目
[
{
id: "10"
author: "Paul Jarvis"
width: 2500
height: 1667
url: "https://unsplash.com/photos/6J--NXulQCs"
download_url: "https://picsum.photos/id/10/2500/1667"
},
...
],
]
今回は一覧で見たいので、このようなデータ構造では使いにくいです。
そのため、サンプルコードではflat()を使ってサブ配列を再帰的に結合し新しい配列を作りました。
const pics = picList.flat();
flat()を使って作った新しい配列は以下の通りです。
一覧で使うのに使いやすいデータ構造になりました。
[
// 1ページ目
{
id: "0"
author: "Alejandro Escamilla"
width: 5616
height: 3744
url: "https://unsplash.com/photos/yC-Yzbqy7PY"
download_url: "https://picsum.photos/id/0/5616/3744"
},
...
// 2ページ目
{
id: "10"
author: "Paul Jarvis"
width: 2500
height: 1667
url: "https://unsplash.com/photos/6J--NXulQCs"
download_url: "https://picsum.photos/id/10/2500/1667"
},
...
]
次のページのデータを取得
サンプルコードで次のページをデータを取得するコードは次の一行だけです。
<button onClick={() => setSize(size + 1)}>もっと見る</button>
useSWRInfinite()のsetSize()に次のページ数を入れるだけで、次のページのデータを取得できます。
最後のページのデータであることを検知する
最後のページのデータであるかは、最後に取得したページのデータがlimitより少ないかで検知します。
サンプルコードにある次のコードで最後のページであるかを検知しています。
const isReachingEnd =
isEmpty || (picList && picList[picList.length - 1]?.length < limit);
isReachingEndがtrueかどうかで、サンプルコード内の次のコードで表示を切り替えています。
{!isReachingEnd ? (
<button onClick={() => setSize(size + 1)}>もっと見る</button>
) : (
"すべて読み込みました。"
)}
https://swr.vercel.app/ja/examples/infinite-loading
まとめ
この記事ではSWRのuseSWRInfinite()
を使って「もっと見る」機能の実装方法をサンプルコードを使ってご紹介しました。
サンプルコードのデモは次の通りです。
今回のサンプルコードでキモになるのがSWRのuseSWRInfinite()です。
useSWRInfinite()を使うことでシンプルに「もっと見る」機能を実装しています。
このサンプルコードのポイントになるのは以下の点です。
- useSWRInfinite()を使ってデータを取得
- useSWRInfinite()で取得したデータを整形
- 次のページのデータを取得
- 最後のページのデータであることを検知する
Reactの参考書をまとめておきます。
コメント