swrを使っていて、無限スクロールを実現するにはどうしたらよいか調べた
ここでいう無限スクロールとは、スクロール量をトリガーにして、次ページのデータを取得し、現在のデータの末尾にそれらを追加することで、取得できるデータがある限り無限にスクロールできるようにするもの
調べたところ公式のドキュメントがあった
大まかな実装方針としては1ページ単位の<Page>
コンポーネントを用意し、それをページ数分ループさせるというもの
function App () { const [cnt, setCnt] = useState(1) const pages = [] for (let i = 0; i < cnt; i++) { pages.push(<Page index={i} key={i} />) } return <div> {pages} <button onClick={() => setCnt(cnt + 1)}>さらに読み込む</button> </div> }
ただ、このときトータルで何件表示されているのかはわからない
そこで、useSWRInfinite
を使ってトータルで何件表示されているかをわかるようにする
https://swr.vercel.app/ja/docs/pagination#useswrinfinite
ドキュメントをそのまま引用させてもらうと、使い方は以下
// 各ページの SWR キーを取得する関数であり、 // その返り値は `fetcher` に渡されます。 // `null` が返ってきた場合は、そのページのリクエストは開始されません。 const getKey = (pageIndex, previousPageData) => { if (previousPageData && !previousPageData.length) return null // 最後に到達した return `/users?page=${pageIndex}&limit=10` // SWR キー } function App () { const { data, size, setSize } = useSWRInfinite(getKey, fetcher) if (!data) return 'loading' // これで、すべてのユーザー数を計算できます let totalUsers = 0 for (let i = 0; i < data.length; i++) { totalUsers += data[i].length } return <div> <p>{totalUsers} ユーザーがリストされています</p> {data.map((users, index) => { // `data` は、各ページの API レスポンスの配列です return users.map(user => <div key={user.id}>{user.name}</div>) })} <button onClick={() => setSize(size + 1)}>さらに読み込む</button> </div> }
size
とsetSize
がページ番号とページ番号の更新で、getKey
関数でページ番号に応じたSWRキーを返すようにする
ページ番号が更新されるたびにdeta
は以下のような構造で返されるので、これを使ってトータルの表示件数を算出する
[ [ { name: 'Alice', ... }, { name: 'Bob', ... }, { name: 'Cathy', ... }, ... ], [ { name: 'John', ... }, { name: 'Paul', ... }, { name: 'George', ... }, ... ], ... ]