Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best Practices for Multiple Mutation Calls in React Query

I'm trying to implement useMutation in the best way possible and maintain some sense of clean code, but I'm running into trouble with how best to manage complicated calls.

For example, when a person creates an account on my application, there are several things that need to happen:

  1. server call to verify recaptcha score
  2. server call to create the user and return login token and verification code that will be sent to the user to verify their account
  3. server call to send the verification code and then store the login cookie and redirect to the next page.

Perhaps the best solution is to try to do all of that in a single call on the backend and I'm willing to do that if it's the best approach, but that feels like mixing too many things into a custom route on the backend.

Assuming I want them all to be separate calls that happen when the person clicks the sign up button, what's the best way to manage those calls?

I've been playing with the onSuccess callbacks for useMutation and calling the next call in the chain in that section, but it feels very bloated. Again, I'm happy with it if it's the best approach, but I would love to hear a suggestion for a better way to do it.

Here is how I did the onSuccess version:

const doSendVerification = useMutation((email)=>sendVerification(email), 
  {
    onSuccess: (data)=>{
        storeCookie(data)
        redirect('nextPath')
      }, 
    onError: (err)=>{handleError(err}
  })

const doCreateUser = useMutation((user)=>createUser(user), 
  {
    onSuccess: (data)=>{doSendVerification.mutate(data)}, 
    onError: (err)=>{handleError(err}
  })

const doVerifyRecaptcha = useMutation((token)=>verifyRecaptcha(token), 
  {
    onSuccess: (data)=>{doCreateUser.mutate(data)}, 
    onError: (err)=>{handleError(err}
  })

Alternatively, I can put them all in one function and use mutateAsync. I know in the case below the onSuccess callbacks would not be included. Something like this:

const handleSubmit = async ()=> {
  try {
    const verified = await doVerifyRecaptcha.mutateAsync(token)
    const newUser = await doCreateUser.mutateAsync(userInfo)
    const sendEmail = await doSendVerification.mutateAsync(emailInfo)
    storeLoginCookie(newUser)
    redirect('nextPath')
  } catch (err){
    handle(err)
  }
}

The second version seems cleaner, but is that because it's shorter or because it's better? I know the error handling isn't as automated as using mutate.

I'm open to any suggestions on how to handle calls with multiple steps or if there's a way I can simplify the code to reduce the number of steps.

Please forgive any typos or inaccuracies in the code below. It's intended to demonstrate the idea of what I'm trying to do rather than be working code. I've created working versions quite similar to both and I'm just not sure if either are the best way to handle this situation.

Thank you for the help and guidance.

like image 466
Brian Gwaltney Avatar asked Jun 17 '26 10:06

Brian Gwaltney


1 Answers

I think you analyzed that pretty well. The three ways for dependent mutations are:

  • all in one mutation
  • chain with onSuccess and mutate
  • chain with mutateAsync

I've answered that in detail here: How can I wait for mutation execution in React Query?

There isn't that much difference between two and three, so it comes down to personal preference.

like image 175
TkDodo Avatar answered Jun 22 '26 11:06

TkDodo



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!