お勉強メモ。嘘ついたらごめんなさい。
React Query で、cacheTime, staleTime と、invalidateQueries, resetQueries あたりの使い分けの話。
お試し用コードは最後に載せてます。
cacheTime, staleTime について
QueryClient
には以下の設定がある。
- cacheTime : 取得済みのデータ(以下「キャッシュ」と呼ぶ)を保持する時間(デフォルト5分)
- staleTime : キャッシュが古くなったと見なして再取得する時間(デフォルト0)
以下のようなコンポーネントの場合、
const SomeComponent = () => { const { data, isLoading } = useQuery("foo", fetchData); if (isLoading) return <div>Loading...</div> return <div>{data.something}</div> }
初回の表示時はキャッシュがないので、データの取得中は「Loading...」が表示される。
2回目以降のデータ再取得時は*1、以下のように動く。
- 前回データ取得時から
cacheTime
もstaleTime
も経過していなければ、キャッシュを表示して終わり - 前回データ取得時から
cacheTime
は経過せず、staleTime
が経過していれば、キャッシュを表示した上で、バックグラウンドで最新のデータを取り直し、取得できた時点で画面へ反映する - 前回データ取得時から
cacheTime
が経過していれば、キャッシュは破棄し、「Loading...」を表示した状態でデータ取得を待機する
つまりデフォルトでは、5分以内に画面を再表示した際は、とりあえず取得済みのキャッシュを表示した状態で、常にバックグラウンドでキャッシュを最新データにリフレッシュする動きとなる。
このあたりの話はDoc の Important Defaults に書いてある。
isLoading と isFetching
上記の補足で、 useQuery
のレスポンスには isLoading
と isFetching
が含まれている。
違いは以下。
- isLoading : キャッシュにデータがなく、データ取得中の状態
- isFetching : キャッシュにデータがある場合も含め、データ取得中の状態
なので通常は、上のコード例のとおり、 isLoading
を見て表示に反映することになると思う。
invalidateQueries と resetQueries
画面から更新したデータを再取得するようなケースでは、取得済みのキャッシュを明示的に破棄したい。
このとき、 QueryClient
のインスタンスに対して、 invalidateQueries
または resetQueries
をコールすることができる。
違いは以下。
- invalidateQueries : キャッシュが古くなったとみなす( =staleTime が経過した状態 )
- resetQueries : キャッシュを破棄する( =cacheTime が経過した状態 )
公式 Doc を読む限り、データ更新後は invalidateQueries
する使い方を想定してるのかなと感じたが、例えば画面から書き込んだデータをすぐに画面に表示するようなケースだと、再fetchが終わるまで、更新前の古いデータ(キャッシュ)が表示されるような動きになってしまうのが微妙だと思う。
最新データが再取得されるまで画面に古いデータを表示したくないときは、 resetQueries
のほうが使い勝手が良いかも。
以上。reset と invalidate の挙動は以下で試せます。
*1:データ再取得のトリガは refetchOnMount, refetchOnWindowFocus, refetchOnReconnect, refetchInterval のオプションで制御する