Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why won't the form state visibly change within the submit button using react form hook?

So I have a sign up form using react-hook-form and I want to make the submit input disabled and display a "Signing in..." message. I've console logged the isSubmitting value within the render and that shows true when I submit and then false not long after however the submit button within the form never updates to reflect the isSubmitting status.

What am I doing wrong? Here is the React Hook Form useFormState docs

From what I can see it should work?

Thanks in advance.

import { useState } from "react"
import { useForm, useFormState } from "react-hook-form"
import useAuth from "Hooks/useAuth"

const SignInForm = () => {
  const [firebaseError, setFirebaseError] = useState(null)
  const { signIn } = useAuth()
  const {
    register,
    handleSubmit,
    resetField,
    control,
    formState: { errors },
  } = useForm()

  const { isSubmitting, isValidating } = useFormState({ control })

  const onSubmit = (data) => {
    signIn(data.email, data.password)
      .then((response) => console.log(response))
      .catch((error) => {
        let message = null

        if (error.code === "auth/too-many-requests") {
          message =
            "Too many unsuccessful attempts, please reset password or try again later"
        }

        if (error.code === "auth/wrong-password") {
          message = "Incorrect password, please try again"
        }

        if (error.code === "auth/user-not-found") {
          message = "User does not exist, please try again"
        }

        resetField("password")
        setFirebaseError(message)
      })
  }

  return (
    <form
      className="signupForm"
      onSubmit={handleSubmit(onSubmit)}
      autoComplete="off"
    >
      {console.log(isSubmitting)}
      {firebaseError && (
        <p className="form-top-error has-text-danger">{firebaseError}</p>
      )}

      <div className="field">
        <input
          type="text"
          className="input formInput"
          placeholder="Email"
          {...register("email", {
            required: {
              value: true,
              message: "Field can not be empty",
            },
            pattern: {
              value:
                /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/,
              message: "Invalid email",
            },
          })}
        />
        {errors.email && (
          <span className="is-block has-text-danger is-size-7">
            {errors.email?.message}
          </span>
        )}
      </div>
      <div className="field">
        <input
          type="password"
          className="input formInput"
          placeholder="Password"
          {...register("password", {
            required: "Field can not be empty",
            minLength: {
              value: 6,
              message: "Must be longer than 6 characters",
            },
          })}
        />
        {errors.password && (
          <span className="is-block has-text-danger is-size-7">
            {errors.password?.message}
          </span>
        )}
      </div>
      <input
        type="submit"
        className="button is-info"
        value={isSubmitting ? "Signing In..." : "Sign In"}
        disabled={isSubmitting}
      />
    </form>
  )
}

export default SignInForm
like image 518
Joe Avatar asked Sep 12 '25 02:09

Joe


2 Answers

I think you need to refactor your onSubmit function to make it async so isSubmitting will stay true during your signIn call.

const onSubmit = async (data) => {
    await signIn(data.email, data.password)
      .then((response) => console.log(response))
      .catch((error) => {
        let message = null

        if (error.code === "auth/too-many-requests") {
          message =
            "Too many unsuccessful attempts, please reset password or try again later"
        }

        if (error.code === "auth/wrong-password") {
          message = "Incorrect password, please try again"
        }

        if (error.code === "auth/user-not-found") {
          message = "User does not exist, please try again"
        }

        resetField("password")
        setFirebaseError(message)
      })
  }

Edit React Hook Form - Async Submit Validation (forked)

like image 133
knoefel Avatar answered Sep 14 '25 17:09

knoefel


onSubmit needs to return a Promise for formState to update correctly.

const onSubmit = (payload) => {
  // You need to return a promise.
  return new Promise((resolve) => {
    setTimeout(() => resolve(), 1000);
  });
};

References:

  • https://react-hook-form.com/api/useform/formstate/
  • https://github.com/react-hook-form/react-hook-form/issues/1363#issuecomment-610681167
like image 26
shrekuu Avatar answered Sep 14 '25 16:09

shrekuu