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を引き続き使える。
onMutate:Mutation実行前- API実行
- 成功なら
onSuccess、失敗ならonError - 最後に
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月

