kkkkkkkkkkkkkkkkk
kkkkkkkkkkkkkkkkk

Reputation: 728

How can I wait for mutation execution in React Query?

I have two API calls in onVerificationCodeSubmit that covering reset password logic. The problem is that newPasswordMutation executes before setRestorePasswordToken(data.restoreToken) in verifyCodeMutation success callback.

How can I wait for it?

Any way I can handle it via React-Query tools?

  const { mutateAsync: verifyCodeMutation } = useMutation(verifyCode, {
    onSuccess: ({ data }) => setRestorePasswordToken(data.restoreToken),
  });

  const { mutateAsync: newPasswordMutation } = useMutation(createNewPassword, {
    enabled: restorePasswordToken,
    onSuccess: () => setPasswordResetSuccessfull(true),
  });

  const onRestorePasswordSubmit = ({ email }) => {
    restorePasswordMutation(email);
  };

  const onVerificationCodeSubmit = async ({ verificationCode, password }) => {
    await verifyCodeMutation({ verificationCode, restoreToken });
    newPasswordMutation({ password, restorePasswordToken });
  };

Upvotes: 18

Views: 29380

Answers (2)

TkDodo
TkDodo

Reputation: 28733

Dependent mutations can basically be solved in 3 different ways:

1) make multiple calls inside the mutateFn:

const mutate = useMutation((data) =>
  axios.post('/something', { data })
    .then((somethingResult) =>
        axios.put('/somethingElse', { somethingResult })
  )
)
<button onClick={() => mutate('data') />

advantage would be one mutation with one loading state. disadvantage would be you can't easily trigger them separately if you'd need to.

2) with mutateAsync:

const mutate1 = useMutation((data) => axios.post('/something', { data }))
const mutate2 = useMutation(somethingResult) => axios.put('/somethingElse', { somethingResult })

<button onClick={async () => {
  try {
    const somethingResult = await mutate1.muteateAsync('data')
    const result = await mutate2.mutateAsync(somethingResult)
  } catch {}
}} />

a bit boilerplate-y and you'd need to combine loading states very likely

3) with mutate and callbacks:

const mutate1 = useMutation((data) => axios.post('/something', { data }))
const mutate2 = useMutation(somethingResult) => axios.put('/somethingElse', { somethingResult })

<button onClick={() => {
    mutate1.mutate('data', {
      onSuccess: mutate2.mutate
    })
}} />

separated, but still quite concise. will get messy with more than 2 mutations, and the end-result would only be available in the onSuccess callback of the second mutation if you need it

Upvotes: 43

kkkkkkkkkkkkkkkkk
kkkkkkkkkkkkkkkkk

Reputation: 728

In case it will help someone: I've just executed second mutation in first one onSuccess

  const { mutateAsync: verifyCodeMutation } = useMutation(verifyCode, {
    onSuccess: ({ data }) => {
      setRestorePasswordToken(data.restoreToken);
      const password = getValues("password");
      newPasswordMutation({ password, restorePasswordToken });
    },
  });

Upvotes: 10

Related Questions