reactjsreact-hook-form

react hook form get error object after triggering validation


When using trigger() on react hook form I can't read the errors object on first attempt. I think this is because the object populates on a subsequent render.

Here is full working example: https://codesandbox.io/s/crimson-firefly-f8ulg7?file=/src/App.tsx

You can see the first time you click submit it logs an empty object and does not set focus. If you click it again then it will work as intended.

Here is example form code:

import "./styles.css";
import classNames from "classnames";

import { useForm } from "react-hook-form";

export default function App() {
  const {
    register,
    handleSubmit,
    trigger,
    watch,
    formState: { errors }
  } = useForm();
  const onSubmit = (data: any) => console.log(data);
  return (
    <div className="App">
      <div className="form">
        <form onSubmit={handleSubmit(onSubmit)}>
          <div className={"row"}>
            <div className="label">Name</div>
            <div
              className={classNames({
                input: true,
                error: errors?.name !== undefined
              })}
            >
              <input {...register("name", { required: "Name is required" })} />
            </div>
          </div>
          <div className="row">
            <div className="label">Company</div>
            <div
              className={classNames({
                input: true,
                error: errors?.company !== undefined
              })}
            >
              <input
                {...register("company", { required: "Company is required" })}
              />
            </div>
          </div>
          <div className="row">
            <div className="label">Tel</div>
            <div
              className={classNames({
                input: true,
                error: errors?.tel !== undefined
              })}
            >
              <input
                {...register("tel", { required: "Telephone is required" })}
              />
            </div>
          </div>
          <div className="row">
            <div className="label">Mobile</div>
            <div
              className={classNames({
                input: true,
                error: errors?.mobile !== undefined
              })}
            >
              <input
                {...register("mobile", { required: "Mobile is required" })}
              />
            </div>
          </div>
          <div className="row">
            <div className="label">Email</div>
            <div
              className={classNames({
                input: true,
                error: errors?.email !== undefined
              })}
            >
              <input
                {...register("email", { required: "Email is required" })}
              />
            </div>
          </div>
        </form>
      </div>

      <div className="button">
        <a
          href="#"
          onClick={() => {
            trigger().then((res) => {
              if (res) {
                
                handleSubmit(onSubmit)();
              } else {
                let elem = errors[Object.keys(errors)[0]]
                  ?.ref as HTMLInputElement;

                elem?.focus();

                // setTimeout(() => {
                //     (errors[Object.keys(errors)[0]]?.ref as HTMLInputElement).focus();
                // }, 10);
                // (errors[Object.keys(errors)[0]]?.ref as HTMLInputElement).focus();

                console.log(errors);
              }
            });
          }}
        >
          Submit
        </a>
      </div>
    </div>
  );
}

I tried using a timeout but it's still empty on the first attempt.

How do I trigger the forms validation and run code based on the results of the validation?

I want to know the errored fields but also have the ref that is included inside the error object.


Solution

  • After reviewing the comment from the other answer you can access the error object by using the getFieldState in the useForm hook and then calling it in your trigger console.log('error object', getFieldState('name').error). You can also just call console.log('field state', getFieldState('name')) to get more info for that field, including the error object.

    I forked your sandbox with the updated code.

    const {
      register,
      handleSubmit,
      trigger,
      getFieldState,
      watch,
      formState: {
        errors
      }
    } = useForm();
    
    <a
    href = "#"
    onClick = {
        () => {
          trigger().then((res) => {
            if (res) {
              handleSubmit(onSubmit)();
            } else {
              let elem = errors[Object.keys(errors)[0]] ?
                .ref as HTMLInputElement;
    
              elem ? .focus();
    
              // setTimeout(() => {
              //     (errors[Object.keys(errors)[0]]?.ref as HTMLInputElement).focus();
              // }, 10);
              // (errors[Object.keys(errors)[0]]?.ref as HTMLInputElement).focus();
    
              console.log("field state", getFieldState("name"));
              console.log("error object", getFieldState("name").error);
              console.log(errors);
            }
          });
        }
      } >
      Submit
    </a>