Stop `useMutation` from re-rendering component and ignore result

Viewed 1532

I have a mutation called like this (this isn't the actual mutation call, but a minimal example):

const App = () => {
  const [myMutation] = useMutation(gql`
    mutation Test($updateUserId: ID!, $updateUserInput: UpdateUserInput!) {
      updateUser(id: $updateUserId, input: $updateUserInput) {
        id
        firstname
        age
      }
    }
  `);

  // Runs every time this component is rendered
  console.log("rendered");

  // Called when the button is clicked
  const update = () => {
    myMutation({
      variables: {
        updateUserId: 1,
        updateUserInput: {
          age: Math.round(Math.random() * 10 + 5) // Set a random age from 5 - 15
        }
      }
    });
  };

  return (
    <>
      <h1>Update Test</h1>
      <button onClick={update}>Update!</button>
    </>
  );
};

Whenever onClick is called, the whole component is re-rendered. This is not what I want, as I don't care about the result of the mutation. Is there any way to stop myMutation from causing a re-render, and ignore the result completely?

4 Answers

useMutation is a hook and it has state in it which cause a re-render

See the useMultation type bellow:

export interface MutationResult<TData = any> {
    data?: TData | null;
    error?: ApolloError;
    loading: boolean;
    called: boolean;
    client: ApolloClient<object>;
}

The loading state is the one causing re-render, so in which component you delcare useMutation it will re-render due to that state


One possible fix is to separate the component with useMutation to another one

Something like this:

function App() {
  return (
    <>
      <Header />  // <-- this coponent won't re-render
      <UpdateUserButton />  // <-- useMutation is in here!
    </>
  );
}

Checkout the live example:

Edit sweet-cohen-4w6ef

Well, if you don't need the data returned by the mutation, you can also pass the ignoreResults option. Data will not be returned from the mutation hook but loading would called neither which prevents a re-render.

https://www.apollographql.com/docs/react/data/mutations/#ignoreresults

const [someMutation] = useSomeMutation({
 ignoreResults: true,
});

This is likely because the mutation is returning a normalised object which this component or a higher component depends on via a hook like useQuery.

If you don't care about the result of the mutation make sure it doesn't return the normalised object.

Something like

mutation SomeMutation ($input: SomeMutationInput!){
  someMutation (input: $input){
    ok
  }
}

Following should work (not tested)

  • Since you don't want re-render, you don't need to use useMutation hook which has state.
  • Instead you can directly import you apollo-client and use mutate on it without using useMutation hook.
  • You can choose to use the result in .then function or get rid of it.
import { apolloClient } from '../yourApolloClientFile';


const App = () => {

  const myMutation = (vars) => apolloClient.mutate({
    mutation: gql`
        mutation Test($updateUserId: ID!, $updateUserInput: UpdateUserInput!) {
          updateUser(id: $updateUserId, input: $updateUserInput) {
            id
            firstname
            age
          }
        }
      `,
    variables: vars
  })
    .then(result => console.log(result))
    .catch(error => console.log(error))


  // Runs every time this component is rendered
  console.log("rendered");

  // Called when the button is clicked
  const update = () => {
    myMutation({
      updateUserId: 1,
      updateUserInput: {
        age: Math.round(Math.random() * 10 + 5) // Set a random age from 5 - 15
      }
    });
  };

  return (
    <>
      <h1>Update Test</h1>
      <button onClick={update}>Update!</button>
    </>
  );
};

Related