TanstackQueryとは?
参考:
Installation | TanStack Query React Docs
Web アプリケーションでの
- サーバー状態の取得(フェッチ)
- キャッシュ
- 同期、サーバーステートの更新
を簡単に扱えるようにするライブラリである
インストール
npm i @tanstack/react-query
useMutation
- クエリとは異なりミューテーションは通常、データの作成/更新/削除やサーバー側での処理に使用される
- Mutationは命令的であり、データ操作のタイミングを明示的にコントロールする。(Queryは宣言的であり、コンポーネントのライフサイクルに基づいて自動的フェッチを行う)
function App() {
const mutation = useMutation({
mutationFn: (newTodo) => {
return axios.post('/todos', newTodo)
},
})
return (
<div>
{mutation.isPending ? (
'Adding todo...'
) : (
<>
{mutation.isError ? (
<div>An error occurred: {mutation.error.message}</div>
) : null}
{mutation.isSuccess ? <div>Todo added!</div> : null}
// ボタンを押されたタイミングで発火
<button
onClick={() => {
mutation.mutate({ id: new Date(), title: 'Do Laundry' })
}}
>
Create Todo
</button>
</>
)}
</div>
)
}
Mutationは下記の状態を持つ(statusかisOOOで判定できる)
- isIdle(status === ‘idle’)
- アイドル状態またはフレッシュ/リフレッシュ状態
- isPending(status === ‘pending)
- 実行中
- isError(status === ‘error’)
- エラー発生
- errorプロパティを使用できる
- isSuccess(status === ‘success’)
- 成功し、データの使用が可能
- dataプロパティを使用できる
リセット
Mutationはエラーやデータをクリアすることもできる
const mutation = useMutation({ mutationFn: createTodo })
return (
<form onSubmit={onCreateTodo}>
// resetメソッドでクリア
{mutation.error && (
<h5 onClick={() => mutation.reset()}>{mutation.error}</h5>
)}
<input
type="text"
value={title}
onChange={(e) => setTitle(e.target.value)}
/>
<br />
<button type="submit">Create Todo</button>
</form>
)
Mutaionのライフサイクルに応じたヘルパーオプション
- onSuccess
- Mutaionが成功した際に発火される。
- onError
- Mutaionが失敗した際に発火される
- onSettled
- Mutaionが成功・失敗いずれかの場合に発火される→onSuccess or onErrorの後に発火
useMutation({
mutationFn: addTodo,
onMutate: (variables) => {
// A mutation is about to happen!
// Optionally return a context containing data to use when for example rolling back
return { id: 1 }
},
onError: (error, variables, context) => {
// An error happened!
console.log(`rolling back optimistic update with id ${context.id}`)
},
onSuccess: (data, variables, context) => {
// Boom baby!
},
onSettled: (data, error, variables, context) => {
// Error or success... doesn't matter!
},
})
Mutate関数について
- useMutationで定義されているもの以外のコールバックをトリガしたい場合にはmutate関数をMutate変数の後に定義することで対応できる
- メリットとしてはコンポーネント固有の処理を行うことができる。ただしmutationが完了する前にコンポーネントがアンマウントされてしまうと追加のコールバックは実行されない
useMutation({
mutationFn: addTodo,
onSuccess: (data, variables, context) => {
// I will fire first
},
onError: (error, variables, context) => {
// I will fire first
},
onSettled: (data, error, variables, context) => {
// I will fire first
},
})
// もしonSuccessで追加の処理がしたい場合はmutate関数内でonSucessに処理を記載すれば
// useMutationのonSucessの後に実行される
mutate(todo, {
onSuccess: (data, variables, context) => {
// I will fire second!
},
onError: (error, variables, context) => {
// I will fire second!
},
onSettled: (data, error, variables, context) => {
// I will fire second!
},
})
非同期のMutate関数
mutateAsyncを使用してmutate関数で非同期を扱うこともできる
const mutation = useMutation({ mutationFn: addTodo })
try {
const todo = await mutation.mutateAsync(todo)
console.log(todo)
} catch (error) {
console.error(error)
} finally {
console.log('done')
}