RTK-Queryで無限ローディングを実装してみた
はじめに
RTK-Queryは、無限ローディングの機能がサポートされてないようで、どうやって実装するのか気になったので試したことをまとめました。
他のデータフェッチライブラリとの比較
react-queryが出してる比較表をみると、RTK-Query以外は対応していました。(Infinite Queries)
SWR
React Query
作ったもの
Cats API を使って、無限ローディング、無限スクロールを実装してみました。
サンプルサイト
ライブラリのバージョン
"@reduxjs/toolkit": "^1.8.0",
"react-redux": "^7.2.6",
"redux": "^4.1.2",
サンプルコード
Cats API
実装の内容
データの取得
まず、useListCatsQuery
にて、現在の表示データと少し余分なデータ(次のページのデータ)を事前に取得します。infinite
関数は、現在のページにとそれ以前に取得した各ページのCatApiの結果を集約する関数です。
// 現在のページ。画面遷移した際にも値を保持していたいのでどこまで読み込んだかのステートはReduxでグローバルに保持
const currentPage = useSelector((state: RootState) => state.currentPage.value)
// 現在のページのCatApiを叩いた結果を取得
useListCatsQuery({ page: currentPage })
// 次のページのCatApiを叩いた結果を取得(すぐ表示できるようにするため)
useListCatsQuery({ page: currentPage + 1 })
// これまでに取得した各ページのCatApiの叩いた結果を集約する関数の実行
const result = infinite(currentPage)
infinite
関数の詳細は、現在のページ数分の要素を持つ配列を作成しループを回し、キャッシュされたCatApiのデータを集約するようにしています。
export const infinite = (currentPage: number) => {
return [...Array(currentPage)].map((_, i) => i + 1).map((page) => {
return api.endpoints.listCats.select({ page })(store.getState()).data
}).flat();
}
api.endpoints.listCats.select
あたりで、RTK-Queryで取得したキャッシュされたデータへのアクセスしています。
キャッシュされたデータへのアクセスの詳細は以下のドキュメントが参考になります。
Accessing cache data and request status information can be performed using the select function property of a query endpoint to create a selector and call that with the Redux state. This provides a snapshot of the cache data and request status information at the time it is called.
データの表示
表示側では、infinite(currentPage)
で取得した result
を表示するようにします。
{
result?.map((cat, index) => (
<Flex key={cat?.id} w={400} flexDirection="column" alignItems="center">
<Text>{`${index + 1}: ${cat?.id}`}</Text>
<Image alt={cat?.id} src={cat?.url} width={400} />
</Flex>
))
}
Load Moreボタンをクリックすると、currentPageがインクリメントされて、result
(infinite(currentPage)
で取得したresult
)の値が更新され、追加されたページのCatApiの取得結果が追加されます。(Load Lessボタン押したらcurrentPageがdecrementされる逆の処理が行われます。)
<Button
onClick={() => {
dispatch(increment())
}}
colorScheme='teal' size='lg'
>
Load More
</Button>
おわりに
SWRはこれまでに使ったことがあって、useSWRInfinite
という無限ローディングを実装するための便利な機能があることを知っていたのですが、RTK-Queryだと機能としては提供されてなかったので実装方法について気になっていて、今回試せてよかったです。
RTK-Queryの場合は無限ローディングの機能は提供されていないものの、データフェッチした値のキャッシュはReduxのstoreに保持されているので、カスタムフックを使わずにセレクターを利用して取得することができ、今回のような実装で無限ローディングを実装できました。(思っていたよりもシンプルに実装できた)
RTK-Queryの無限スクロールについては、いろいろとディスカションしてる様子がみれて勉強になったので、今後もウォッチしておこうと思いました。
Discussion