Mutations with useMutation
Post data to APIs with useMutation, handle loading/error states, and invalidate queries on success.
Mutations with useMutation is a free React Academy lesson on CoddyKit — lesson 3 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the React Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
Welcome
useMutation Basics
import { useMutation } from '@tanstack/react-query';
const { mutate, isLoading, isError } = useMutation({
mutationFn: (newPost) => fetch('/api/posts', {
method: 'POST',
body: JSON.stringify(newPost),
}).then(r => r.json()),
});Calling mutate
<button onClick={() => mutate({ title: 'New Post' })}>
Create Post
</button>Callbacks: onSuccess, onError, onSettled
useMutation({
mutationFn: createPost,
onSuccess: (data) => {
console.log('Created:', data);
navigate('/posts/' + data.id);
},
onError: (error) => {
toast.error(error.message);
},
})Invalidating Queries After Mutation
import { useQueryClient } from '@tanstack/react-query';
const queryClient = useQueryClient();
const { mutate } = useMutation({
mutationFn: createPost,
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['posts'] });
},
});mutateAsync for await Syntax
const { mutateAsync } = useMutation({ mutationFn: createPost });
async function handleSubmit() {
try {
const post = await mutateAsync({ title: 'Draft' });
navigate('/posts/' + post.id);
} catch (err) {
setError(err.message);
}
}Disabling Submit During Mutation
const { mutate, isPending } = useMutation({ mutationFn: saveItem });
<button onClick={() => mutate(item)} disabled={isPending}>
{isPending ? 'Saving...' : 'Save'}
</button>Optimistic Updates with onMutate
useMutation({
mutationFn: likePost,
onMutate: async (id) => {
await queryClient.cancelQueries({ queryKey: ['posts'] });
const prev = queryClient.getQueryData(['posts']);
queryClient.setQueryData(['posts'], old => old.map(p =>
p.id === id ? { ...p, likes: p.likes + 1 } : p));
return { prev };
},
onError: (err, id, ctx) => queryClient.setQueryData(['posts'], ctx.prev),
onSettled: () => queryClient.invalidateQueries({ queryKey: ['posts'] }),
})Mutation State Reset
const { mutate, isError, reset } = useMutation({ /* ... */ });
{isError && (
<>
<p>Error!</p>
<button onClick={reset}>Try Again</button>
</>
)}Multiple Mutations in Parallel
await Promise.all([
mutateAsync({ id: 1, title: 'First' }),
mutateAsync({ id: 2, title: 'Second' }),
]);Quick Check
Recap
Up Next
Frequently asked questions
Is the “Mutations with useMutation” lesson free?
Yes — the full text of “Mutations with useMutation” is free to read here on the web, and the React Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the React Academy course, upgrade to CoddyKit PRO.
What will I learn in “Mutations with useMutation”?
Post data to APIs with useMutation, handle loading/error states, and invalidate queries on success. You practise React Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start React Academy?
No prior experience is required. React Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 3 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “Mutations with useMutation” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this React Academy lesson?
Yes. Every React Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.