Reactで無限スクロールを実装する方法【react-infinite-scroller】
ReactでWebページを作成していると無限スクロールを実装する機会があると思います。スクロールしたら非同期でデータを取得して、無限にスクロールできる機能のことです。YouTubeにも実装されているので見たことがあると思います。
今回はこの無限スクロールをReactで実装するライブラリのreact-infinite-scroller
を紹介します。
react-infinite-scrollerのインストール
まずはreact-infinite-scrollerのインストールを行います。以下のどちらかのコマンドを実行してインストールします。
npm install react-infinite-scroller --save
yarn add react-infinite-scroller
react-infinite-scrollerを使ってみる
インストールが完了したら、実際に使ってみましょう。次のサンプルは読みこむたびに数字が1つずつ大きくなるリストを作っています。スクロールバーを見ると縮んでいるので無限にスクロールできているのが分かりますよね。
import {useState} from 'react';
import InfiniteScroll from "react-infinite-scroller"
export default function Index() {
//表示するデータ
const [list, setList] = useState([])
//項目を読み込むときのコールバック
const loadMore = (page) => {
setList([...list, page])
}
//各スクロール要素
const items = (
<ul>
{list.map((value) => <li>{value}</li>)}
</ul>);
//全体のスタイル
const root_style = {
marginLeft : "50px",
marginTop : "50px",
}
//ロード中に表示する項目
const loader =<div className="loader" key={0}>Loading ...</div>;
return (
<div style={root_style}>
<InfiniteScroll
loadMore={loadMore} //項目を読み込む際に処理するコールバック関数
hasMore={true} //読み込みを行うかどうかの判定
loader={loader}> {/* 読み込み最中に表示する項目 */}
{items} {/* 無限スクロールで表示する項目 */}
</InfiniteScroll>
</div>
)
}
react-infinite-scrollerの使い方は、簡単です。
まず初めに必要なライブラリーをインポートします。import InfiniteScroll from "react-infinite-scroller"
で取り込みInfiniteScroll
で使用します。
次に各属性を設定します。以下は、このライブラリーでよく使う属性の一覧です。
-
loadMore
:ユーザーがスクロールしてコンテンツの読み込み時に実行される -
pageStart
:ロードする際のページ番号。loadMore
のコールバック関数の引数に渡される。 -
hasMore
:ロードするコンテンツがまだあるかの判定。falseで読み込み終了。 -
loader
:ロード中に表示する内容。
先ほどのコードでは、loadMore
属性で読み込む際にlist
にページ番号を追加していいます。そしてhasMore
属性をtrueに設定することでスクロールしても無限に表示されるようになっています。
最後に、スクロール対象の項目を定義します。子コンポーネントに設定します。今回のソースでは随時、読み込まれて追加される配列をリスト形式で出力しています。これによりリストをスクロールしても無限に表示できるようなっているのです。
Web APIを使って無限スクロールを実現する
先ほどのサンプルはテスト用です。実際、使うとなるとWeb APIで作成することが多いでしょう。なのでここではWeb APIを使った実装方法を紹介します。
以下のソースはAPIから読み込んだ配列情報を出力しています。ただし、今回の場合は取得できなかった場合(pageが5以上)、読み込み処理を終了しています。
Web APIの処理(Next.js)
export default (req, res) => {
const page = req.query.page //クエリパラメータの取得
let result = [];
if (page < 5) {
//0~99を返す
result = [...Array(100).keys()].map(i => i + page * 100)
}
//処理成功
res.statusCode = 200
res.json(result)
}
無限スクロール処理
import {useState} from 'react';
import InfiniteScroll from "react-infinite-scroller"
export default function Index() {
const [list, setList] = useState([]); //表示するデータ
const [hasMore, setHasMore] = useState(true); //再読み込み判定
//項目を読み込むときのコールバック
const loadMore = async (page) => {
const response = await fetch(`http://localhost:3000/api/test?page=${page}`); //API通信
const data = await response.json(); //取得データ
//データ件数が0件の場合、処理終了
if (data.length < 1) {
setHasMore(false);
return;
}
//取得データをリストに追加
setList([...list, ...data])
}
//各スクロール要素
const items = (
<ul>
{list.map((value) => <li>{value}</li>)}
</ul>);
//全体のスタイル
const root_style = {
marginLeft : "50px",
marginTop : "50px",
}
//ロード中に表示する項目
const loader =<div className="loader" key={0}>Loading ...</div>;
return (
<div style={root_style}>
<InfiniteScroll
loadMore={loadMore} //項目を読み込む際に処理するコールバック関数
hasMore={hasMore} //読み込みを行うかどうかの判定
loader={loader}> {/* 読み込み最中に表示する項目 */}
{items} {/* 無限スクロールで表示する項目 */}
</InfiniteScroll>
</div>
)
}
この処理では、loadMore
メソッド内のfetch
でWeb APIのデータを取得して表示しています。引数にページ番号が渡るため、その値を使って対象のデータを追加しています。
そして、データが無ければhasMore
をfalseに設定し読み込みを終了することで無駄な通信をせずに済むようになっているのです。
まとめ
- Reactで無限スクロールを使うなら
react-infinite-scroller
がおススメ - loadMoreに読み込み時のコールバック関数を設定する
- hasMoreで読み込みを行うかどうかの判定を行う
Discussion
参考になりました!!