TanStack QueryのuseQueryにて、refetchIntervalとstaleTimeを組み合わせたときの動作を確認してみた

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秒ごとにステータスが staleloading の間で切り替わっています。

また、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秒ごとにステータスが freshloading の間で切り替わっています。なお、 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