We have learned how to use useQuery and structure your application when using react query to communicate with your server. This time around we are going to learn how to send data to your server with a seamless user experience. Let’s get straight into this bad boy. 😏

Why useMutation?

Very different from queries, mutation can be used to post, delete or update your data with react query, even any side effects from your server. And useMutation is the hook used to perform this.

useMutation In Action ⚔️

Following our layer pattern from the scaffolding guide we are going to write our add planet API in our api.js layer as

const addPlanet = async (data) => {
  const { name } = data;
  const body = { name };
  return axiosInstance({
    url: "planets",
    method: "POST",
    data: body,
  }).then(({ data }) => {
    return data;

Once we have the api layer ready we then consume it in our custom hooks hooks.js as

const useAddPlanet = () => {
  const queryClient = useQueryClient();
  queryClient.setMutationDefaults(["add-planet"], {
    mutationFn: (data) => addPlanet(data),
    onMutate: async (variables) => {
      const { successCb, errorCb } = variables;
      return { successCb, errorCb };
    onSuccess: (result, variables, context) => {
      if (context.successCb) {
    onError: (error, variables, context) => {
      if (context.errorCb) {
  return useMutation(["add-planet"]);

we are setting our mutation defaults as the first argument being the query key and then our mutation function like we did in react query. The new kids in the town here are onMutate, onSuccess and onError.

  • onMutate: On mutate can be used to handle some side effects when the request is in the process.
  • onSuccess: On success is used to do changes when the request is successfully served.
  • onError: On error is used to handle if your request is failed or let’s say has some error like 404.

And then we return our mutation with the query key with useMutation. 🚀🚀

Consuming Our Mutation

Now to consume our mutation hook inside our component we can do something like

  const addPlanetMutation = useAddPlanet();

and on callback to our add button we do

  function handleAddPlanet() {
    const planetName = newPlanetInput.current.value;
    if (planetName === "") {

    const mutationArgs = {
      name: newPlanetInput.current.value,

    newPlanetInput.current.value = null;

We have our mutation arguments ready as mutationsArgs and in them, we have our success and error callbacks which are to be called inside our custom hook.

Success and Error Callbacks

In our error callback, we can add some sort of alert or a way to inform the user that the request they just made has failed and in our success callback we fetch our data.

What Is invalidateQueries?

Invalidate queries come in very handy when we are trying to fetch our data again amid some side effect. And we can pass query key as the argument which tells react query exactly which request or which cached data to fetch again.

  const successCb = () => {

  const errorCb = () => {};

Invalidate Query Loading

Once we invalidate our query we have to show some sort of indicator to our user that the data is currently being fetched and this too is provided by react query 🤯🤯

  const { data, isLoading, isFetching } = usePlanets();

isFetching is used to show the loader again and also addPlanetMuttion.isLoading.

  {isLoading || addPlanetMutation.isLoading || isFetching ? (
      <InfinitySpin width="500" color="blue" />
  ) : (


Wrap Up

OUFFFF 😅😅. This one was very long but I hope you stuck by my side till the very end because if you get this bit it can come in real handy in your reactJS application as well. This is it for this one and I hope to see you at the next one. So this is not a goodbye.

Avatar photo
👋 Hey, I'm Hasan Shahid
Hi I'm Hasan! I'm a software engineer with decent experience in full stack web development. My tech stack includes JS/TS, React, Native and anything JS. I keep learning and love football.

💬 Leave a comment

Your email address will not be published. Required fields are marked *

We will never share your email with anyone else.