⛳
React Query: Query Client のメソッド備忘録
Conclusion
- 以下の5つのメソッドについては最低限把握しておくとよさそう
Premise
- React 17.0.2
- TypeScript 4.6.2
- React Query(@tanstack/react-query) 4.3.4
Contents
React Query を使用するにあたり、キャッシュ管理についての理解は必須だろうということで Query Client のメソッドについて調べました。
個人的に残しておきたい部分のみかつ記事執筆時点の情報になるので、最新情報は公式ドキュメント参照でお願いします。
Query Client とは
QueryClient
はキャッシュ管理のために使用されるクラス- キャッシュからの値の取得、削除等々
- コンポーネント内部では useQueryClient を使用することでインスタンスを取得でき、それに対して各種メソッド経由でキャッシュ管理が可能
- 各クエリのキャッシュ設定(キャッシュの有効期限等)は
useQuery
のオプションで設定可能ですが、キャッシュした後のものについては QueryClient を使用することで操作する- 基本的に 1 度のみ取得させておく設定のクエリについて、特定の操作をトリガーにキャッシュ無効化・再取得の実行を行いたいケース等
const App: VFC = () => {
const store = setupStore()
const queryClient = new QueryClient()
return (
<QueryClientProvider client={queryClient}>
<BrowserRouter>
<Router />
</BrowserRouter>
</QueryClientProvider>
)
}
const SomeComopnent = () => {
const queryClient = useQueryClient()
return <></>
}
メソッド
queryClient.fetchQuery()
- クエリのフェッチとキャッシュのために使用される非同期関数
- フェッチの結果を必要とせずにクエリを取得したい(プリフェッチで遷移前などで値を取得しておきたいようなケース)では
prefetchQuery
メソッドを使用する -
useQuery
の方を使用することが多そうなのであまり使用しないかな?
try {
const data = await queryClient.fetchQuery(queryKey, queryFn, {
staleTime: 10000,
})
} catch (error) {
console.log(error)
}
queryClient.fetchInfiniteQuery()
-
fetchQuery
とほぼ同じだが、一度キャッシュした値をInfinity
で持ち続ける -
fetchQuery
にオプションを渡すことでも設定できる他、useQuery
を使用することが多いため出番はなさそう
queryClient.prefetchQuery()
- プリフェッチのための非同期関数
- データをキャッシュに詰めるための関数なのでデータを返すなどはしない
await queryClient.prefetchQuery(queryKey, queryFn)
// デフォルトで queryFn を設定している場合は以下でもOK
await queryClient.prefetchQuery(queryKey)
queryClient.prefetchInfiniteQuery()
-
prefetchQuery
のキャッシュInfinity
版
queryClient.getQueryData()
- 既にキャッシュに存在するデータを取得するための同期関数
- データが存在しない場合には
undefined
を返す - 上位コンポーネントでフェッチ済みのデータへアクセスする場合などに使えそう
- Options
queryKey?: QueryKey: Query Keys filters?: QueryFilters: Query Filters
const data = queryClient.getQueryData(queryKey)
queryClient.getQueriesData(): [queryKey:QueryKey, data:TData | unknown][]
- 複数のクエリのキャッシュデータを取得するために使用できる同期関数
- 渡された queryKey あるいは queryFilter にマッチするクエリのみが返される
- データが存在する場合は、
[クエリキー, データ]
のタプル型の配列になるconst data = queryClient.getQueriesData(queryKey | filters)
- オプション
queryKey: QueryKey | filters: QueryFilters
queryClient.setQueryData
- クエリのキャッシュデータを即座に更新するために使用される同期関数
- クエリが存在しない場合は作成される
- デフォルトのキャッシュ有効時間である 5 分いないにクエリフックによって使用されない場合はガベージコレクションされる(消える)
- 一度に複数のクエリを更新したりクエリのキーを部分的にマッチさせるためには、
setQueriesData
を使用する -
setQueryData
とfetchQuery
の違いは、setQueyData
は同期処理であり同期的にデータを取得できることを前提としていること- 非同期にデータを取得する必要がある場合には、クエリキーを用いてリフェッチするか
fetchQuery
を使用して非同期取得を行うのが良い
- 非同期にデータを取得する必要がある場合には、クエリキーを用いてリフェッチするか
- オプション
- queryKey: QueryKey - updater: TData | (oldData: TData | undefined) => TData | undefined - 関数以外を渡すと、データはその値で更新される - 関数を渡すと、古いデータの値を受け取り、新しい値を返すことが期待される
queryClient.setQueryData(queryKey, updater) ## 値を渡して更新 setQueryData(queryKey, newData) ## 更新関数を使用 setQueryData(queryKey, oldData => newData)
queryClient.setQueriesData
- 複数のクエリをフィルタリングしたり、クエリキーを部分的にマッチさせたりしてキャッシュされたデータを即座に更新するために使用される同期関数
- オプション
- queryKey: QueryKey: Query Keys | filters: QueryFilters - 第一引数にクエリキーが渡された場合、パラメータに部分的にマッチするクエリキーが更新される - フィルタ関数が渡された場合、そのフィルタにマッチするクエリキーが更新される - updater: TData | (oldData: TData | undefined) => TData
queryClient.getQueryState
- 既に存在するクエリの状態を取得するために使用される同期関数
- オプション
- queryKey?: QueryKey - filters?: QueryFilters
const state = queryClient.getQueryState(queryKey) console.log(state.dataUpdatedAt)
queryClient.invalidateQueries
- クエリキーや、クエリのプロパティ/状態など、機能的にアクセス可能なものをもとに、キャッシュ内の 1 つまたは複数のクエリを無効化したり再取得するために使用される関数
-
デフォルトではマッチするクエリは全て即座に無効化され、アクティブなクエリはバックエンドでリフェッチされる
- アクティブなクエリをリフェッチせずに無効化させたい場合は
refetchType: none
を使用する- アクティブなクエリ =
useQuery
やそれに類するメソッド等でアクティブにレンダリングされるクエリ
- アクティブなクエリ =
- 非アクティブなクエリもリフェッチさせたい場合は、
refetchType: all
を指定する
- アクティブなクエリをリフェッチせずに無効化させたい場合は
- オプション(細部は省略)
queryKey?: QueryKey
filters?: QueryFilters
options?: InvalidateOptions
queryClient.refetchQueries
- 特定の条件に基づいてクエリを再取得するために使用される関数
- この関数は全てのクエリのリフェッチが完了した時に
resolve
されるプロミスを返す- デフォルトではリフェッチが失敗してもエラーを投げないが、オプションで
throwOnError
を設定することで投げるようにできる
- デフォルトではリフェッチが失敗してもエラーを投げないが、オプションで
- オプション
queryKey?: QueryKey
filters?: QueryFilters
options?: RefetchOptions
// refetch all queries: await queryClient.refetchQueries() // refetch all stale queries: await queryClient.refetchQueries({ stale: true }) // refetch all active queries partially matching a query key: await queryClient.refetchQueries(['posts'], { type: 'active' }) // refetch all active queries exactly matching a query key: await queryClient.refetchQueries(['posts', 1], { type: 'active', exact: true })
queryClient.cancelQueries
- クエリキーやクエリのプロパティ/状態をもとに、送信中のクエリをキャンセルできる
-
発信中のクエリのリフェッチが解決した時に楽観的なアップデートを妨害しないようにキャンセルする必要がある場合が多いため、楽観的な更新を行う場合に最も有効
-
楽観的な更新 = サーバーからの通信結果待たずに UI を更新すること
UI が嘘をつく? UX デザインにおける「楽観的な更新」と SPA での作り方 - カミナシ エンジニアブログ
-
楽観的な更新 = サーバーからの通信結果待たずに UI を更新すること
- オプション
queryKey?: QueryKey
filters?: QueryFilters
await queryClient.cancelQueries(['posts'], { exact: true })
queryClient.removeQueries
- クエリキーやその他の機能的にアクセス可能なプロパティ/状態に基づいて、クエリをキャッシュから削除するために使用する関数
- オプション
queryKey?: QueryKey
filters?: QueryFilters
queryClient.removeQueries(queryKey, { exact: true })
queryClient.resetQueries
- キャッシュ内のクエリを、クエリキーやその他機能的にアクセス可能なプロパティ/状態に基づいて、初期状態にリセットすることができる
- 全てのサブスクライバーを削除する
clear
とは異なりサブスクライバーに通知され、invalidateQueries
と異なりクエリをロード前の状態にリセットする - クエリがアクティブな場合はリフェッチされる
-
- mutate で値の更新をした場合など、
onSuccess
で実行することでisLoading
を true にできる
- mutate で値の更新をした場合など、
-
- 全てのアクティブなクエリのリフェッチが完了するまで Promise を返す
- オプション
queryKey?: QueryKey
filters?: QueryFilters
options?: ResetOptions
queryClient.resetQueries(queryKey, { exact: true })
queryClient.isFetching
- キャッシュ内にフェッチ中のクエリ(バックグラウンド、新しいページの読み込み、無限クエリ結果の読み込みを含む)の数を表す整数を返す関数
-
useIsFetching
という hooks を使用できる - オプション
queryKey?: QueryKey
filters?: QueryFilters
if (queryClient.isFetching()) { console.log('At least one query is fetching!') }
queryClient.isMutating
- キャッシュ内でフェッチ中の mutation の数を返す関数
-
useIsMutating
という hooks が提供されているので基本そちらを使用する - オプション
filters: MutationFilters
if (queryClient.isMutating()) { console.log('At least one mutation is fetching!') }
queryClient.getLogger
- クライアント作成時に設定されたロガーを返す関数
const logger = queryClient.getLogger()
queryClient.getDefaultOptions
- クライアントの作成時または setDefaultOptions で設定されたデフォルトのオプションを返す
const defaultOptions = queryClient.getDefaultOptions()
queryClient.setDefaultOptions
- queryClient の設定を動的に設定するために使用される関数
- 以前設定されていたものは上書きされる
queryClient.setDefaultOptions({ queries: { staleTime: Infinity, }, })
queryClient.getQueryDefaults
- 特定のクエリに対して設定されているデフォルトのオプションを返す
- 複数のクエリのデフォルトが与えられたクエリキーにマッチする場合、 最初にマッチしたものが返される
const defaultOptions = queryClient.getQueryDefaults(['posts'])
queryClient.setQueryDefaults
- 特定のクエリのデフォルトオプションを設定できる
- 最初にマッチしたデフォルトが getQueryDefaults によって返されるので、登録する順番は、 一般的でないキーから最も一般的なキーまでとする必要がある
- オプション
-
queryKey: QueryKey
: Query Keys options: QueryOptions
queryClient.setQueryDefaults(['posts'], { queryFn: fetchPosts }) function Component() { const { data } = useQuery(['posts']) }
-
queryClient.getMutationDefaults
- 特定の mutation に設定されているデフォルトのオプションを返す
const defaultOptions = queryClient.getMutationDefaults(['addPost'])
queryClient.setMutationDefaults
- 特定の mutation のデフォルトオプションを設定するために使用される関数
-
setQueryDefaults
などと同様に設定する順序に注意 - オプション
mutationKey: string | unknown[]
options: MutationOptions
queryClient.setMutationDefaults(['addPost'], { mutationFn: addPost }) function Component() { const { data } = useMutation(['addPost']) }
queryClient.getQueryCache
- クライアントが接続しているクエリキャッシュを返す
const queryCache = queryClient.getQueryCache()
queryClient.getMutationCache
- クライアントが接続しているミューテーションキャッシュを返す
const mutationCache = queryClient.getMutationCache()
queryClient.clear
- 接続されているすべてのキャッシュをクリアする
queryClient.clear()
queryClient.resumePausedMutations
- ネットワークに接続されていないために一時停止しているミューティングを再開するために使用する関数
queryClient.resumePausedMutations()
Discussion