Orval生成React Queryフックの使い方メモ【TanStack Query v5対応】

JavaScript

Orvalで生成したReact Queryフックの使い方を、自分用に整理し直す。以前のメモはTanStack Query v4系の書き方が混ざっていて、v5ではそのまま使えない部分があったので修正した。

前提はOrvalのclient: 'react-query'でTanStack Query用のフックを生成する構成。実際の関数名や引数はOpenAPI定義とOrval設定によって変わるので、最終的には生成されたコードの型を見る。

QueryとMutationの使い分け

基本的には、データ取得はQuery、作成・更新・削除などサーバー側を変更する処理はMutationとして考える。

  • Query:主にGET、データ取得・キャッシュ・再取得
  • Mutation:POST / PUT / PATCH / DELETEなど、データ変更

OrvalではOpenAPIから型付きのQuery / Mutationフックを自動生成できる。

Hooksはトップレベルで呼ぶ

Orvalが生成するuseQuery系・useMutation系もReact Hooksなので、コンポーネントやカスタムHookのトップレベルで呼ぶ。

// OK
const query = useGetTask(taskId)
const mutation = useUpdateTask()

// NG
if (taskId) {
  const query = useGetTask(taskId)
}

条件付きで取得したい場合はHook自体を条件分岐させず、enabledなどを使う。

Query系フック

生成される形は設定やOrvalのバージョンによって違うが、使う側のイメージは次のような形。

const {
  data,
  isPending,
  isLoading,
  isFetching,
  isError,
  error,
  refetch,
} = useGetTask(taskId, {
  query: {
    enabled: Boolean(taskId),
    staleTime: 30_000,
    refetchOnWindowFocus: false,
  },
})

TanStack Query v5の状態名

v5ではstatus: 'loading'がstatus: 'pending'へ変わり、従来のisLoading相当は基本的にisPendingになった。

ただしQueryには現在もisLoadingがあり、これはisPending && isFetchingを表す派生値。初回の実際のフェッチ中だけを見たい場合には便利だが、以前と意味が同じではないので注意する。

  • isPending:まだ成功データがないpending状態
  • isLoading:pendingかつfetching中
  • isFetching:初回・バックグラウンドを含め通信中
  • isError:エラー状態
  • refetch:手動再取得

QueryのonSuccess / onError / onSettledはv5で削除

ここが以前のメモから大きく変わったところ。TanStack Query v5では、useQueryのonSuccess、onError、onSettledは削除されている。

そのため、Query取得後の副作用を昔のように次の場所へ書く前提にはしない。

// v5のQueryではこの考え方にしない
query: {
  onSuccess: () => {
    // ...
  },
}

データの変化に応じた処理が本当に必要なら、用途に応じてuseEffectなどへ分離する。単に画面表示用の値を作るだけなら、副作用にせず取得したdataから計算する。

Mutation系フック

MutationはHookをトップレベルで作っておき、実際の実行はボタン、フォーム送信、イベント処理などからmutateまたはmutateAsyncを呼ぶ。

const {
  mutate,
  mutateAsync,
  isPending,
  isError,
  error,
  data,
} = useUpdateTask({
  mutation: {
    onSuccess: () => {
      console.log('更新成功')
    },
    onError: (error) => {
      console.error(error)
    },
  },
})

MutationではisLoadingではなくisPending

TanStack Query v5ではMutationの実行中判定はisPendingを使う。以前のメモにあったisLoadingはv4系の書き方。

const mutation = useUpdateTask()

if (mutation.isPending) {
  // 送信中
}

mutateとmutateAsync

  • mutate:イベントから実行して、結果処理をMutationオプション側に寄せるときに使いやすい
  • mutateAsync:Promiseを返すので、awaitして後続処理を順番に書きたいときに使う
try {
  const result = await mutateAsync({
    data: formData,
  })

  // 成功後の処理
} catch (error) {
  // エラー処理
}

Mutationのコールバック

Queryと違い、MutationではonMutate、onSuccess、onError、onSettledを引き続き使える。

  1. onMutate:Mutation実行前
  2. API実行
  3. 成功ならonSuccess、失敗ならonError
  4. 最後にonSettled

楽観的更新をする場合はonMutateで現在値を退避し、失敗時にonErrorで戻す形を使う。

更新後は関連Queryをinvalidateする

Mutationが成功してもQueryキャッシュは自動で都合よく更新されるとは限らないので、関連する一覧や詳細を再取得したい場合はqueryClient.invalidateQueriesを使う。

const queryClient = useQueryClient()

const mutation = useUpdateTask({
  mutation: {
    onSuccess: async () => {
      await queryClient.invalidateQueries({
        queryKey: ['tasks'],
      })
    },
  },
})

Orvalは設定によってquery key取得用の関数やinvalidate用ヘルパーも生成できるので、文字列を直接書くより生成コードを利用できる場合はそちらを優先する。

Orval側で確認しておく設定

Orvalではoutput.override.queryで、Query・Mutation・Suspense・Infinite Queryなどの生成を調整できる。

export default defineConfig({
  api: {
    output: {
      client: 'react-query',
      override: {
        query: {
          useQuery: true,
          useMutation: true,
          useInvalidate: true,
          useGetQueryData: true,
        },
      },
    },
  },
})

生成されるフックの引数や戻り値はOrval設定、HTTPメソッド、mutatorの有無などでも変わるため、ネットの記事より生成されたTypeScript型を正として確認するのが確実。

自分用まとめ

Query
- Hookはトップレベル
- 条件取得はenabled
- v5のQueryではonSuccess/onError/onSettledなし
- isPending / isLoading / isFetchingの意味を区別

Mutation
- Hookはトップレベル
- 実行はmutate / mutateAsync
- 実行中はisPending
- onSuccess/onError/onSettledは利用可能
- 成功後は必要に応じてinvalidateQueries

Orval
- 実際の引数は生成コードの型を確認
- query keyやinvalidateヘルパーが生成されていれば活用

公式情報メモ

最終更新:2026年9月

タイトルとURLをコピーしました