この記事は、2021年 Reactアドベントカレンダー 24日目の記事です。
メリークリスマス。
はじめに
データをよしなにキャッシュしてくれるReactQuery と React.Suspenseを組み合わせて使ってみたらあまりに便利で、自分の中でデータキャッシュの革命が起きたのでそのことを書く。
ReactQueryとは
今更感があるのでここでは書かない。
React.Suspenseとは
今更感があるのでここでは書かない。
ReactQuery導入以前
WebAPI経由で取得したデータをキャッシュしたい場合にはCustomHooksの中でRecoilを使って自前で頑張っていたが、データをリフレッシュするタイミングでローディング状態に入りデータが無くなりSuspenseにfallbackされてしまいUX的に厳しいものがあったりでなかなかつらい思いをしていた。
感動した点
ほぼ QueryClient / Query のオプション依存ではあるが、
-
Suspenseのオプション
これをtrueにしておくと、最初のデータの取得が完了するまではSuspenseにフォールバックしてくれるので、適当な粒度でSuspenseを差し込んでおけばデータがnullかどうかを気にせずほぼ同期的に扱える。便利。 -
keepPreviousDataのオプション
これをtrueにしておくと、裏でデータをロードしつつロードが完了するまではSuspenseにフォールバックすること無く最後に返した値をそのまま返してくれる。データのロードが完了したタイミングで新しいデータに差し替わり、自動で再描画してくれる。
これによって、画面がちらつくことなくスムーズに新しいデータを表示することができる。便利。
QueryClient単位ではなくQuery単位でこのオプションを有効/無効にすることも可能なので、基本的に有効にしておいて古いデータが表示されると困るような画面で使う場合のみ無効にする、という使い方もできる。便利。 -
APIクライアントの実装はそのまま使い回せる
ReactQuery がやっていることはデータのキャッシュだけなので、それまで使っていたAPIクライアントの実装はそのまま使い回すことができる。
導入以前からUI → CustomHooks → Repository → API Client
という構成にしていたので、Repository にReactQueryを差し込むことでAPIClientの実装は完全にそのまま使えた。
CustomHooksも、データがnullかどうか気にしている部分を削除したくらいで、インターフェース的には大きな変更無しで使うことができた。数が多いので大変だったが。
改めて考えてみると
RecoilによるデータのキャッシュをCustomHooksのレイヤーでやっていたのがそもそもの誤りで、Repositoryのレイヤーでやっていたら意外とそこまで辛くなかったのかもしれない。
ReactQueryが提供してくれている柔軟なキャッシュキーや、裏でデータをフェッチする機構を作るのは大変だったと思うが。
終わりに
ReactHooksによる再描画の仕組みの強力さを改めて知る意味でも良い体験だった。
逆に、それがまともに使われていない古いコードベースのプロジェクトを触るのが最近つらい。
ReactQueryを業務で使い始めたのが3日前、感動したのが2日前、この記事を書こうと思い立ったのが昨日、書いているのが今日、ということで、コードは何もない上にだいぶ書き殴りになってしまったが気にしない。
とりあえず、当面の間は非同期的に取得するnullになり得るデータのキャッシュはReactQueryで、それ以外の、nullかどうかを気にせずに済むデータ (UIのstateとか) はRecoilでキャッシュ、がよさそう。