TanStack Queryの useQuery
には refetchInterval
という設定値があります。
以下の公式ドキュメントにある通り、これは定期的にデータ取得を行うための設定のようです。これを使うことにより、APIへのポーリングも容易に実装できそうです。
refetchInterval: number | false | ((data: TData | undefined, query: Query) => number | false)
Optional If set to a number, all queries will continuously refetch at this frequency in milliseconds If set to a function, the function will be executed with the latest data and query to compute a frequency
一方、前回見た通り、 useQuery
には staleTime
という設定値もあります。
こちらはキャッシュしたデータが古くなったとみなす時間を指定します。staleTime
が経過したタイミングでデータが自動的に更新されます。
staleTime: number | Infinity
Optional Defaults to 0 The time in milliseconds after data is considered stale. This value only applies to the hook it is defined on. If set to Infinity, the data will never be considered stale
これら2つの設定を組み合わせるとどのような挙動になるのか気になったので、試してみたときのメモを残します。
目次
環境
- React 18.2.0
- TanStack Query 4.32.6
環境は以前の記事と同じため、詳しくはそちらを参照してください。
Reactにて、useStateやuseEffectを使っていたところをTanStack Queryに置き換えてみた - メモ的な思考的な
staleTimeはデフォルト(0)、refetchIntervalは2秒の場合
まずは refetchInterval
のみ設定し、動作を確認してみます。
コンポーネントの準備
前回の記事同様、時計を表示しつつ useQuery
を実行するコンポーネントを用意します。
import {useQuery} from "@tanstack/react-query"; import {DefaultApi} from "../../../../../types"; import {Clock} from "../../../../components/Clock"; const queryFn = () => new DefaultApi().fetchFishes({headers: {Prefer: 'dynamic=true'}}).then(async (response) => { // 待ち時間を入れる await new Promise(resolve => setTimeout(resolve, 1000)) return response.data.fishes }) const Page = () => { const {data} = useQuery({ queryKey: ['PollingWithDefaultSettings'], queryFn: queryFn, refetchInterval: 2000, }) return ( <> <Clock /> {data && ( <ul> {data.map(f => <li key={f.id}>ID: {f.id} / Name: {f.name}</li>)} </ul> )} </> ) } export default Page
動作確認
画面を表示すると、 refetchInterval
の2秒 + APIのレスポンス待ちの1秒の合計3秒ごとに、画面に表示されるデータが変更されています。
TanStack QueryのDevToolsに注目すると、2秒ごとにステータスが stale
と loading
の間で切り替わっています。
また、ChromeのNetworkタブを見ると、定期的にAPIへリクエストを飛ばしていることがわかります。
staleTimeは6秒、refetchIntervalは2秒の場合
次は、 staleTime
が経過する前に、 refetchInterval
の時間を迎えた場合、APIへリクエストを飛ばすのかどうかを確認してみます。
コンポーネントの準備
先ほどのコンポーネントと似ていますが、useQuery
のオプションとして refetchInterval
に加え staleTime
も設定している点が異なります。
それ以外は同じ実装です。
import {useQuery} from "@tanstack/react-query"; import {DefaultApi} from "../../../../../types"; import {Clock} from "../../../../components/Clock"; const queryFn = () => new DefaultApi().fetchFishes({headers: {Prefer: 'dynamic=true'}}).then(async (response) => { // 待ち時間を入れる await new Promise(resolve => setTimeout(resolve, 1000)) return response.data.fishes }) const Page = () => { const {data} = useQuery({ queryKey: ['PollingWithDefaultSettings'], queryFn: queryFn, refetchInterval: 2000, staleTime: 6000, // ★これを追加★ }) return ( <> <Clock /> {data && ( <ul> {data.map(f => <li key={f.id}>ID: {f.id} / Name: {f.name}</li>)} </ul> )} </> ) } export default Page
動作確認
画面を表示すると、先ほどの例と同じく、 refetchInterval
の2秒 + APIのレスポンス待ちの1秒の合計3秒ごとに、画面に表示されるデータが変更されています。
TanStack QueryのDevToolsに注目すると、先ほどと異なり、3秒ごとにステータスが fresh
と loading
の間で切り替わっています。なお、 loading
は一瞬表示される程度です。
また、ChromeのNetworkタブを見ると、定期的にAPIへリクエストを飛ばしています。
これより、たとえ staleTime
が経過してなくても、 refetchInterval
はキャッシュを利用せずにAPIへリクエストを飛ばすということがわかりました。
ソースコード
Githubに上げました。
https://github.com/thinkAmi-sandbox/tanstack_prism_generouted-example
今回のプルリクはこちらです。
https://github.com/thinkAmi-sandbox/tanstack_prism_generouted-example/pull/5