1

I use TanStack/query to handle mutations for registration/login to a Drupal 9 website.

If registration is successful, I automatically log the user in.

With React 17, the following code allows the user to register and then immediately logs the user in. However, with React 18 and createRoot, registration succeeds but login fails because onSuccess no longer has access to the variable formData (console.log() in onSuccess returns an empty object for formData).

const onSubmit = (submitData: DrupalLoginFormInput) => {
  setIsLoading(true);
  mutateRegister.mutate(submitData);
};

export const useMutationRegister = (
  formData: DrupalLoginFormInput,
  setIsLoading: React.Dispatch<React.SetStateAction<boolean>>,
): UseMutationResult<HttpResponse, string, DrupalLoginFormInput> => {
  const mutateLogin = useMutationLogin();
  return useMutation(
    (registerData: DrupalLoginFormInput) =>
      postRegisterUser(registerData, platform),
    {
      onSuccess: () => {
        // console.log('mutateRegister succeeded', response, formData);
        // Log in with the newly registered info.
        const registeredDataToLogin = {
          mail: formData.mail,
          pass: formData.pass,
        };
        mutateLogin.mutate(registeredDataToLogin);
      },
    },
  );
};

export type DrupalLoginFormInput = {
  mail: string;
  pass: string;
};

The React 18 batching deep dive suggests using flushSync() to disable batching, so I tried this:

const onSubmit = (submitData: DrupalLoginFormInput) => {
  flushSync(() => {
    setIsLoading(true);
    mutateRegister.mutate(submitData);
  });
};

However, login is still broken (formData is not available in onSuccess).

If I keep my app with React 18 but revert createRoot() to the old way (render(<App />, container);), then login works again. However, I want to use createRoot() because that unlocks the new React 18 features.

How can I fix my code so that the formData variable doesn't get removed before I access it in onSuccess?

Patrick Kenny
  • 4,515
  • 7
  • 47
  • 76
  • 1
    we haven't changed anything in this regard from v3 to v4. It would be good if you could show a minimal codesandbox reproduction that works with v3 but fails with v4, thanks. – TkDodo Aug 14 '22 at 06:42
  • 1
    @TkDodo Ok, thanks. It may have been in upgrading react or react-hook-form then. I will try to isolate the issue and make a codesandbox. – Patrick Kenny Aug 14 '22 at 07:02
  • 1
    @TkDodo Traced the problem to `createRoot()` in React 18. This is not a v3/v4 issue. – Patrick Kenny Aug 16 '22 at 02:41

1 Answers1

0

I was using flushSync() incorrectly. You need to call flushSync() each time you want the DOM to update.

Bad code:

const onSubmit = (submitData: DrupalLoginFormInput) => {
  flushSync(() => {
    setIsLoading(true);
    mutateRegister.mutate(submitData);
  });
};

Good code, state updates correctly:

const onSubmit = (submitData: DrupalLoginFormInput) => {
  flushSync(() => {
    setIsLoading(true);
  });
  flushSync(() => {
    mutateRegister.mutate(submitData);
  });
};
Patrick Kenny
  • 4,515
  • 7
  • 47
  • 76