React Hook Form Controller Issues

Summy picture Summy · Apr 28, 2020 · Viewed 10.7k times · Source

I have been using react hook form library with native elements but would like to switch to custom components using the Controller API.

I am having an issue with my custom input component updating React state but not updating the ref inside the form state. Thus, a required field is always marked as invalid and I cannot submit my form.

Here is a demo of my issue: https://codesandbox.io/s/react-hook-form-controller-bofv5

It should log out form data upon submission - but submission never happens because form is not valid.

Answer

Elias picture Elias · Apr 28, 2020

I think I have narrowed down your issue. First I removed the rules={{ required: true }} from the controller and tried the form. It told me firstName: undefined. Then I commented out the onChange attribute. After that, the form is working fine. It seems that onChange should be used if you want to provide a custom value extractor. The value needs to be returned from the function. An example of a simple input would be this: onChange={([{target}]) => target.value} reference. Additionally, it is important to note that handleSubmit extracts some internal state with the values, like that you don't need to keep track of those yourself.

This updated component seems to be working:

function App() {
  const { control, handleSubmit, errors } = useForm();
  // const [data, setData] = useState({ firstName: "" });

  const onSubmit = data => console.log(data);

  // const onChangeHandler = e => {
  //   const { name, value } = e.target;
  //   const _data = { ...data };
  //   _data[name] = value;
  //   setData(_data);
  // };

  return (
    <>
      {/* <p>{JSON.stringify(data)}</p> */}
      <form onSubmit={handleSubmit(onSubmit)}>
        <Controller
          as={Input}
          name="firstName"
          id="firstName"
          label="First Name"
          control={control}
          // value={data.firstName}
          rules={{ required: true }}
          errors={errors.firstName}
          // onChange={([e]) => onChangeHandler(e)}
        />

        <input type="submit" />
      </form>
    </>
  );
}

Just a side note, I've never worked with this library so only trust me as far as you can toss me.