TanStack Queryは神フレームワーク
株式会社パルケの手を動かすCTO、みつるです。
今年に入ってからリリースしたプロダクトでは、TanStack Query (旧React Query)を全面的に採用しました。
無料でずっと話せるミーティングアプリ パルケミート
とにかく簡単につながる無料ビジネスチャット パルケトーク
このツールを使い倒した結果、これはいちライブラリの枠に収まらない、開発の考え方そのものを変える神フレームワークだと思うようになりました。
今回はその神ってるところを紹介したいと思います。
TanStack Queryとは
公式のトップページより
Powerful asynchronous state management for TS/JS, React, Solid, Vue and Svelte
パワフルな非同期状態管理ツールという事です。
ただのデータ取得&キャッシュの便利ツールではない、という気持ちが伝わってきます。
state managementと言っている部分に、どちらかというとReduxやRecoilのような状態管理ツールの枠に入るようです。
そして、非同期を前提にしているという点がTanStack QueryをTanStack Query足らしめていると言えるでしょう。
TanStack Queryのここが神
コードジェネレーターで自動生成されるhooksが神
TanStack Queryをそのまま使うと、クエリのキャッシュキーを自分で決めないといけません。
万が一キャッシュキーがかぶったら検知しずらいバグになってしまうので、気を使います。
ところが、GraphQL Code Generatorを使えば、その心配は不要です。
クエリーのキーと、Variableと戻り値の型までついたhooksが自動生成されます。
あとはその生成されたhooksをインポートして使うだけです。
特にクエリ毎の細かいコンフィグが不要なら、データ取得処理が1行で済んでしまいます。
const { data } = useGetProfileQuery({ id: uid });
この1行の中に、以下の全てが含まれているというのが驚きです。
- エラーハンドリング ※デフォルトのクエリで定義している場合
- fetch処理 ※GraphQL Code Generatorで設定している場合
- エラー時のリトライ
- 同時に同じクエリが走った場合の間引き(deduping)
- フォーカス時や再接続時の自動再フェッチ
- fetchしたデータのキャッシュと、一定時間後のガベージコレクション
- キャッシュがあれば先にそのデータを返し、裏でクエリを実行して成功したら新しいデータで再レンダリング
ここまで楽しちゃっていいのでしょうか。神です。
脳死で無限スクロールできるのが神
無限スクロールの要件を実現しようと思うと考える事がたくさんあって頭痛くなりませんか?
私はなります。
できれば要件を落とすようにお願いしたいところです。
TanStack Queryには最初から無限スクロールが備わっているので、その仕組みに乗っかればほとんど何も考えずに流れ作業で無限スクロールが実現できてしまいます。
もちろん、GraphQL Code Generatorも無限スクロールに対応していますので、自動生成されたコードをインポートすれば恐ろしく少ないコードで無限スクロールが実現できてしまいます。
const { data, fetchNextPage, hasNextPage } = useInfiniteSearchMessageQuery(
{},
{
getNextPageParam(lastPage) {
return lastPage.searchMessage?.pageInfo.endCursor;
},
},
);
こんなに簡単に無限スクロールできちゃっていいのでしょうか。神です。
コンポーネントの実装が極めてシンプルになる
TanStack Queryで実装していると、useStateやuseEffectをほとんど書かなくていい事に気づきます。
useStateやuseEffectも神APIです。
しかしその神APIも多用するとコンポーネントの処理が複雑になって処理を追うのが難しくなってきます。
TanStack Queryでは、QueryまたMutationの結果を、onSuccessでハンドリングできますので、useStateやuseEffectが不要になりコンポーネントがシンプルになっていきます。
たとえばデータ更新後のイベントデータ送信のような処理は、onSuccessに書いておけばコードがスッキリと見通しがよくなります。
const setReactionMutation = useSetReactionMutation({
onSuccess(_, variables) {
if (variables.operation === 'ADD') {
// イベント送信
sendEvent({
event: 'TALK_ACTION',
});
}
},
});
データが必要であれば、全ての場所にqueryを書いておいて、その戻り値のdataを使うようにすれば、TanStack Queryが適度にクエリ処理を間引いてくれて取得したデータを返してくれます。
fetchしたデータをstoreに詰めて、他の場所ではそのstoreを参照する、といったような処理は不要です。
何も考えずに処理が必要な場所全てで同じqueryを置いておけばいいのです。
考えること、認知すべきことが劇的に軽減されます。神です。
いい感じに永続化してくるのが神
TanStack QueryのキャッシュはLocal StorageやAsync Storageなどに永続化しておいて、次の起動時に取り出して復元する事ができます。
Local Storageの容量が不安であればIndexed DBを使うようにしても良いでしょう。
高頻度の更新で負荷をかけたくない場合は、throttleTime
を設定して同期処理を間引く事もできてしまいます。ここまで設定できるなんて、神です。
/**
* Storageへの永続化
* Native: AsyncStorage
* Web: LocalStorage
*/
const persister = createAsyncStoragePersister({
throttleTime: 3000,
storage: AsyncStorage,
});
この結果、クエリを利用するコンポーネントではそのデータがローカルストレージから来ているのか、リモートのサーバーから来ているのか意識するする必要がなく、最短でデータを自動で表示してくれます。
ローカルストレージとサーバーのデータは勝手に同期されるので、データ同期について何も考える必要がありません。
データの永続化がこんなに簡単に実現できてしまっていいのでしょうか。神です。
キャッシュのデータを自由に取得、更新できるのが神
TanStack Queryの大きな特徴として、キャッシュのデータを自由に更新できるAPIが備わっているという事があります。
キャッシュキーさえわかれば、queryClientからいつでも最新のデータを取り出したり、キャッシュを更新したりできます。
データ更新時にサーバーの更新結果をまたずに画面に変更結果を表示したい場合などに多用します。
// キャッシュのデータ取得
const data = queryClient.getQueryData(queryKey)
// キャッシュのデータ更新
queryClient.setQueryData(queryKey, updater)
GraphQL Code Generatorで、exposeQueryKeys
をONにしておけば、生成されたクエリのgetKey()メソッドでキーが取得できますので、安心してキャッシュを取得・更新できます。
const query = useUserDetailsQuery(...)
const key = useUserDetailsQuery.getKey({ id: theUsersId })
必要があれば、自分で簡単にキャッシュを取得・更新できる。神です。
React Nativeでも使える
多少追加の設定、コードが必要ですが、それさえ済ませば、WebでもReact Nativeでもそのまま利用できます。
Nativeアプリでは、オフラインアクセスの体験が重要ですが、データ取得を全てTanStack Query経由としておけばオフラインでも問題なく動作するアプリが構築できます。
React Nativeにも優しいフレームワーク。神です。
最後に
最後に、株式会社パルケでは、無料で誰でも簡単に使えるミーティングアプリ、チャットアプリをTanStack Queryを最大限に活用して構築しました。
興味がありましたらぜひ利用してみてください。
Discussion