
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.