Unlike queries, mutations are typically used to create/update/delete data or perform server side-effects. For this purpose, React Query exports a useMutation
hook.
Assuming the server implements a ping mutation, that returns "pong" string, here's an example of the most basic mutation:
const PingPong = () => {const [mutate, { status, data, error }] = useMutation(pingMutation)const onPing = async () => {try {const data = await mutate()console.log(data)// { ping: 'pong' }} catch {// Uh oh, something went wrong}}return <button onClick={onPing}>Ping</button>}
Just as with useQuery
you can also use booleans if you'd like:
const [mutate,{ isIdle, isLoading, isError, isSuccess, data, error },] = useMutation(pingMutation)
Mutations without variables are not that useful, so let's add some variables to closer match reality.
To pass variables
to your mutate
function, call mutate
with an object.
// Notice how the fetcher function receives an object containing// all possible variablesconst createTodo = ({ title }) => {/* trigger an http request */}const CreateTodo = () => {const [title, setTitle] = useState('')const [mutate] = useMutation(createTodo)const onCreateTodo = async e => {// Prevent the form from refreshing the pagee.preventDefault()try {await mutate({ title })// Todo was successfully created} catch (error) {// Uh oh, something went wrong}}return (<form onSubmit={onCreateTodo}><inputtype="text"value={title}onChange={e => setTitle(e.target.value)}/><br /><button type="submit">Create Todo</button></form>)}
Even with just variables, mutations aren't all that special, but when used with the onSuccess
option, the Query Cache's invalidateQueries
method and the Query Cache's setQueryData
method, mutations become a very powerful tool.
Note that since version 1.1.0, the mutate
function is no longer called synchronously so you cannot use it in an event callback. If you need to access the event in onSubmit
you need to wrap mutate
in another function. This is due to React event pooling.
// This will not workconst CreateTodo = () => {const [mutate] = useMutation(event => {event.preventDefault()return fetch('/api', new FormData(event.target))})return <form onSubmit={mutate}>...</form>}// This will workconst CreateTodo = () => {const [mutate] = useMutation(formData => {return fetch('/api', formData)})const onSubmit = event => {event.preventDefault()mutate(new FormData(event.target))}return <form onSubmit={onSubmit}>...</form>}
It's sometimes the case that you need to clear the error
or data
of a mutation request. To do this, you can use the reset
function to handle this:
const CreateTodo = () => {const [title, setTitle] = useState('')const [mutate, { error, reset }] = useMutation(createTodo)const onCreateTodo = async e => {e.preventDefault()await mutate({ title })}return (<form onSubmit={onCreateTodo}>{error && <h5 onClick={() => reset()}>{error}</h5>}<inputtype="text"value={title}onChange={e => setTitle(e.target.value)}/><br /><button type="submit">Create Todo</button></form>)}
The latest TanStack news, articles, and resources, sent to your inbox.