React Query: Query Client のメソッド備忘録

2022/12/02に公開

Conclusion

Premise

  • React 17.0.2
  • TypeScript 4.6.2
  • React Query(@tanstack/react-query) 4.3.4

Contents

React Query を使用するにあたり、キャッシュ管理についての理解は必須だろうということで Query Client のメソッドについて調べました。

個人的に残しておきたい部分のみかつ記事執筆時点の情報になるので、最新情報は公式ドキュメント参照でお願いします。

QueryClient - React Query

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 を使用する
  • setQueryDatafetchQuery の違いは、 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

  • クエリキーやクエリのプロパティ/状態をもとに、送信中のクエリをキャンセルできる
  • 発信中のクエリのリフェッチが解決した時に楽観的なアップデートを妨害しないようにキャンセルする必要がある場合が多いため、楽観的な更新を行う場合に最も有効
  • オプション
    • 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 にできる
  • 全てのアクティブなクエリのリフェッチが完了するまで 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: QueryKeyQuery 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