あるReactの仕事で、画面にスクロールして行くと次々と新しいデータが表示されるInfinite-scroll(無限スクロール)を使ってみようと、React用のInfinite-scrollライブラリーを調べてみました。
昔行った約2万行のjQueryで書かれたフロントエンドをReactに置き換えた開発事例のアプリでも一部にInfinite-scrollを採用していましたが、独自に実装していました😅、今どきなら良いライブラリーがあるに違いないと検索したところ。
10 Best React Infinite Scroll Libraries in 2022 | Openbase
10 Best React Infinite Scroll Librariesin 2022 | Openbaseという良いサイトを見つけました!
このOpenbaseは、開発者がより良いオープンソースソフトウェアを選択できることを目的としたサービスで高名なY Combinatorも出資しています。
さて、ここにリストされているライブラリーは日々順位が変わっているのですが、私が最初に見たときの10件を今回の目的で私の独断で採点してみました。
今回の目的は
- 縦スクロールのみ、要素のサイズは一定のシンプルなInfinite Scroll
- スクロールしながらデータが必要になった時点で取得するLazy Loadingが出来ること
- シンプルなライブラリーが望ましい
です。
ライブラリー | 最終更新 | シンプル | Lazy Loading |
---|---|---|---|
react-virtuoso | 〇 | △ | X |
pro-gallery | 〇 | △ | △ |
react-virtualized | 〇 | △ | 〇 |
react-window | △ | △ | △ |
react-list | 〇 | 〇 | X |
react-infinite-scroll-component | X | 〇 | 〇 |
react-masonry-infinite | X | 〇 | 〇 |
react-infinite-scroller | 〇 | 〇 | 〇 |
react-infinite-scroll-hook | 〇 | △ | 〇 |
最終更新は最終コミットが、半年年以内なら〇、1年以内なら△、それ以前はXにしました。シンプルは私の主観です。Lazy LoadingもGitHubのドキュメントを見て決めましたが見落としもあるかもしれません。
上の表に見ると明らかなように今回はreact-infinite-scroller を使うことにしました。
サンプルコード
さてサンプルコードを書くにはデータを提供するサーバーが必要ですが、GraphQL and REST API for Testing and Prototyping | GO RESTというテスト用APIサーバー・サイトを使いました。同様なサイトは多数ありますが、このサイトはデータのGETだけなら認証が不要なので採用しました。
コード
- ① Bulma CSSを使って見かけを少し良くしました
- ② GO RESTのusers APIの戻り値の型を定義しました
- ③ APIアクセスは速いので、開発時にはスリープ関数があると便利です
- ④ APIで取得したusersデータの入るState
- ⑤ まだ読み込み可能データがあるかを示すState
- ⑥ 1ページ単位で、APIでデータを取得する関数
- ⑦ 取得したusersデータをusers Stateに連結し格納
- ⑧ APIからデータが取得出来なければcountは0になるのでhasMore Stateをfalseに、0より大きければhasMore Stateをtrueにセットしています
import { useState } from 'react';
import InfiniteScroll from 'react-infinite-scroller';
import 'bulma/css/bulma.css' // ← ①
type UserType = { // ← ②
id: number,
name: string,
email: string,
gender: "male" | "female" | "unknown",
status: "active" | "inactive"
}
const sleep = (sec: number) => new Promise(resolve =>
setTimeout(resolve, sec * 1000)); // ← ③
const App = () => {
const [users, setUsers] = useState<UserType[]>([]) // ← ④
const [hasMore, setHasMore] = useState(true) // ← ⑤
const loadUser = async (page: number) => { // ← ⑥
const URL = `https://gorest.co.in/public/v2/users?&page=${page}`
await sleep(1.0)
const response = await fetch(URL)
const usersData: UserType[] = await response.json()
const count = usersData.length
console.log(`GET ${URL} count=${count}`)
setUsers([...users, ...usersData]) // ← ⑦
setHasMore(count > 0) // ← ⑧
}
return (
<div className="container mt-4 p-4"
style={ {height:500, width: "50%",overflow: "auto"} }>
<InfiniteScroll // ← ⑨
pageStart={1} // ← ⑩
loadMore={loadUser} // ← ⑪
loader={<progress key={0} // ← ⑫
className="progress is-success is-radiusless"></progress>}
hasMore={hasMore} // ← ⑬
useWindow={false} > // ← ⑭
<ul className="list"> // ← ⑮
{users.map((user, ix) => // ← ⑯
<li className="list-item p-2"
style={ {borderBottom: "solid 1px #ccc"} } key={ix}>
{user.name}
</li>
)}
</ul>
</InfiniteScroll>
</div>
);
}
export default App;
- ⑨ InfiniteScrollのコンポーネント
- ⑩ pageStartは開始時のページ番号
- ⑪ 読み込み関数の指定
- ⑫ データ読み込み中に表示されるJSX(コンポーネント)
- ⑬ まだ取得すべきデータがあるかの指定、この値がtrueの場合loadMoreで指定された関数が呼び出されます
- ⑭ 今回は特定のdiv内でスクロールするので
useWindow=false
を指定 - ⑮
<InfiniteScroll ...> 〜 </InfiniteScroll>
の間にスクロールする表示用JSXを書きます - ⑯ 今回のスクロール部分はusersのnameプロパティーを
<ul>
,<li>
で表示しています
画面キャプチャー
動作中の画面をキャプチャーしてみました(アニメーションGIFです)。
まとめ
react-infinite-scrollerを使って、簡単にInfinite Scrollが実装できました。
ただし、あまり更新されていないのは気になります・・・
しかし、コードを見ると286行の小さなライブラリーなので開発が止まっても自分でメンテできそうですね。😊