🧭

TanStack Query(React Query)のcacheTimeとstaleTimeを出来るだけわかりやすく解説する

2022/12/11に公開

TanStack Query(React Query)はとても便利で良く使っているのですが、
「cacheTime」と「staleTime」の違いってなんだっけ?と毎回調べるハメになるのでまとめてみました。

https://tanstack.com/query/v4/docs/guides/caching

ちなみにそれぞれのデフォルトの設定は以下です。

the default cacheTime of 5 minutes  // 5分
the default staleTime of 0.  // 0秒

色々検証した結果、はっきり言ってテキストだけでこの仕様を理解するのは無理だと思いますw
自分でモックを作って検証をしないと間違った理解で実装をしてしまう可能性があるのでオプションの指定には十分に注意しましょう。

今回使用したdemoのコードは以下
Next.jsを使用。
https://github.com/underground0930/react-query-demo

apiディレクトリでモックapiを作成。
以下のアルファベットの文字をランダムで1文字表示するAPIです。
Loadingがわかりやすいように5秒のdelayを入れています。

https://github.com/underground0930/react-query-demo/blob/main/pages/api/hello.ts

⭐️demo1

「cacheTime:5分 / staleTime:0秒」

画面下についているのはライブラリのdevtoolになります。
画面右のapiコール数が合っていない所はキャプチャによって何回か撮り直した箇所です
気にしないでいただけると、、(撮り直す元気がない)


↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
(A).最初は、APIを呼ぶコンポーネントは閉じています。


↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
(B).開きました。
キャッシュは無いので、LoadingとFetchingは両方走ります。
データをAPIから取りにいっています。
devtoolのステータスも「fetching」になっています。
ローディングを5秒間待ちます。


↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
(C). APIからデータをgetしてアルファベットが表示されました。
staleTimeが0秒なので、速攻でステータスが「stale」になります。
キャッシュされたデータはもう古いものとみなされます。
同一コンポーネントが表示され続ける限りなにも起こりません。


↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
(D). 閉じます。
対象のコンポーネントが閉じたため、ステータスが「inactive」になります。
キャッシュは存在しています。
閉じた状態のまま10秒ほど待ちます。


↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
(E). 開いて再描画します。すると、isFetchingが走ります。
なぜなら、キャッシュはもう古いものとみなされているからです。(staleTimeが過ぎているため)
その間は、古い前回の文字は表示され続けたままです。

10秒しか経ってないため、cacheは破棄されません。


↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
(F). 「fetching」が終わると、文字列も更新されました。

バックグラウンドでデータが更新されてデータが更新されたら文字が差し変わります

⭐️demo2

「cacheTime:20秒 / staleTime:8秒」


↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
(A).新たにデータをapiからコールします、もちろんキャッシュはありません


↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
(B).データを取得して文字列が表示されました。
「staleTimeが8秒」なので、8秒経過するまではキャッシュは新しいとみなされます。
ステータスも「fresh」ですね。


↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
(C).8秒経過したのでステータスが「stale」になります。


↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
(E).閉じます。ここで20秒以上待ちます。


↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
(F).20秒経ったので、chcheが破棄されました。


↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
(G). コンポーネントを開いた途端、isLoadingも一緒に走ります。
この時、キャッシュは破棄されているので文字列は表示されていません。
ここがfetchingとloadingの違いになります。

ちなみに、どうやら
「cacheTime」がカウントされているのは、当該コンポーネントが閉じている時
「staleTime」がカウントされているのは、コンポーネントの有無によらず通しで
のようでした。(間違っていたら、ごめんなさい、教えてください)

⭐️demo3

「cacheTime:1分 / staleTime:Infinity」


↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
staleTimeにはInfinityも設定出来ます。
こうなると、コンポーネントを開いている間は、ずっと「flesh」のままです。
データが更新されることはありません。

コンポーネントを閉じて1分経過するか、強制的にキャッシュをクリアする

しかありません。そんな時は下の方にある2つのメソッドを使います。
(demoの方にもボタンがあります)

// isFetchingが走る、つまり当該キャッシュを古い、とみなす
// データが更新されるまで、古いデータが表示され続ける
queryClient.invalidateQueries({ queryKey: ["hello"] })

// isLoadingが走る、つまり当該キャッシュを破棄する
// データが更新されるまで、何も表示されない
queryClient.resetQueries({ queryKey: ["hello"] })

最後に

テキストの説明だけだとこの辺を理解するのは難しいと思ったので、この記事を書きました。
案件毎にこの辺の値は注意して設定することにより、表示速度やサーバーの負荷軽減に役立ちそうです。
何か、ご意見、ご感想、アドバイスありましたら教えていただけるとありがたいです。

参考にさせていただいた記事

https://oita.oika.me/2021/09/06/react-query-reset-vs-invalidate

Discussion