Skip to content

FAQs

frequently asked question.

Performance of React Hook Form

Performance is one of the primary goals for building this custom hook. React Hook Form relies on uncontrolled component, hence the reason why the register function occurs at the ref. This approach will reduce the amount of re-rendering occurring due to user typing or value changing. Components mount to the page is much quicker as well because they are not controlled. For mounting speed, I have completed a quick comparison test which you can refer to by this repo link.


How to create an accessible input error and message?

React Hook Form is based on Uncontrolled Component, which gives you the ability to build an accessible custom form easily.

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

export default function App() {
  const { register, handleSubmit, errors } = useForm();
  const onSubmit = data => console.log(data);

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input
        type="text"
        aria-invalid={errors.firstName ? "true" : "false"}
        aria-describedby="firstNameError"
        name="firstName"
        ref={register({ required: true })}
      />
      <span id="firstNameError" style={{ display: errors.firstName ? "block" : "none" }}>
        This field is required
      </span>

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

Does it work with Class Components?

No, not out of box. but you can build a wrapper around it and use in your Class Component.

You can’t use Hooks inside of a class component, but you can definitely mix classes and function components with Hooks in a single tree. Whether a component is a class or a function that uses Hooks is an implementation detail of that component. In the longer term, we expect Hooks to be the primary way people write React components.

How to reset the form?

There are two methods to clear the form.

  • HTMLFormElement.reset()

    This method does the same thing as clicking a form's reset button, and only clearsinput/select/checkbox values.

  • React Hook Form API: reset()

    React Hook Form's reset method will reset all fields value, and also will clear all errors within the form.


How to initialize form values?

React Hook Form relies on uncontrolled component. With an uncontrolled component, you can specify a defaultValue or defaultChecked to an individual field. However, the hook itself does provide an easier way to initialise all input values too. Example below:

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

export default function App() {
  const { register, handleSubmit } = useForm({
    defaultValues: {
      firstName: "bill",
      lastName: "luo",
      email: "bluebill1049@hotmail.com"
    }
  });
  const onSubmit = data => alert(JSON.stringify(data));

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input name="firstName" ref={register} />
      <input name="lastName" ref={register} />
      <input name="email" ref={register} />

      <button type="submit">Submit</button>
    </form>
  );
}

How to share ref usage?

React Hook Form needs ref to collect the input value, however, you may want to use ref for other purposes (eg. scroll into the view). The following example will show you how.

import React, { useRef } from "react"
import { useForm } from "react-hook-form"

export default function App() {
  const { register, handleSubmit } = useForm()
  const firstNameRef = useRef()
  const onSubmit = data => alert(JSON.stringify(data))

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input name="firstName" ref={(e) => {
        register(e)
        firstNameRef.current = e // you can still assign to ref
      }} />
      <input name="lastName" ref={(e) => {
        // register's first argument is ref, and second is validation rules
        register(e, { required: true })
      }} />

      <button>Submit</button>
    </form>
  );
}

What if you don't have access to ref?

You can actually register an input without a ref. In fact, you can manually setValue, setError and triggerValidation.

Note: Because ref has not been registered, React Hook Form won't be able to register event listeners to the inputs. This means you will have to manually update value and error.

import React, { useEffect } from "react";
import { useForm } from "react-hook-form";

export default function App() {
  const { register, handleSubmit, setValue, setError } = useForm();
  const onSubmit = data => alert(JSON.stringify(data));

  useEffect(() => {
    register({ name: "firstName" }, { required: true });
    register({ name: "lastName" });
  }, [])

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input
        name="firstName"
        onChange={e => setValue("firstName", e.target.value)}
      />
      <input
        name="lastName"
        onChange={e => {
          const value = e.target.value;
          if (value === "test") {
            setError("lastName", "notMatch")
          } else {
            setValue("lastName", e.target.value)
          }
        }}
      />
      <button>Submit</button>
    </form>
  );
}

Browser Support?

React Hook Form support all major browsers.

For legacy IE11 support, you can import react-hook-form IE 11 version.

import { useForm } from 'react-hook-form/dist/react-hook-form.ie11'

If you encounter:

Object doesn't support property or method 'find'

You should try to add this find polyfill to the top of your app.js


Why is first keystroke is not working?

Double check if you are using value instead of defaultValue.

React Hook Form is built based on uncontrolled input, which means you don't need to change input value via state by onChange. Hence you don't need value at all, in fact, you only need defaultValue for initial input value.


Testing failed due to MutationObserver?

If you have difficulty during testing and the issue was caused by MutationObserver. Make sure you install mutationobserver and import this package in your test setup.js file.

npm i mutationobserver-shim

React Hook Form, Formik or Redux Form?

First of all, all libs try to solve the same problem which is making form building experience easy and great. However, there are some fundamental differences between the three, react-hook-form is built with uncontrolled input in mind and tries to provide your form with best performance and least re-render if possible. On top of that, react-hook-form is built by React Hook and used as hook, which means there is no Component for you to import. Here are some of the detail differences:

React Hook Form

Formik

Redux Form

Componentuncontrolled & controlledcontrolledcontrolled
Renderingminimum re-renderre-render according to local state changes which means as you type in the input.re-render according to state management lib (Redux) changes which means as you type in the input.
APIHooksComponent (RenderProps, Form, Field) + HooksComponent (RenderProps, Form, Field)
Package sizeSmall
react-hook-form@4.0.0
6.2KB
Medium
formik@2.0.1
14.4KB
Large
redux-form@8.2.6
27KB
ValidationBuilt-in & YupBuild yourself or YupBuild your yourself or Plugins
Learning curveLowMediumMedium
StatusMedium Community: New lib and growingLarge Community: Well established form lib in the communityLarge Community: Well established form lib in the community

Can it work with Controlled component?

Short answer: Yes

React-hook-form is not recommending you to build form controlled, however you can still achieve that easily.

The trick to using watch API to monitor each input's change and assign to value prop.

Alternatively, you can use our wrapper component Controller which take care those custom register for you.

import React from "react";
import { useForm, Controller } from "react-hook-form";
import { TextField } from "@material-ui/core";

function App() {
  const { control, handleSubmit } = useForm();

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

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <Controller
        as={<TextField />}
        name="firstName"
        control={control}
        defaultValue=""
      />
      
      <input type="submit" />
    </form>
  );
}
CodeSandbox
import React, { useEffect } from "react";
import { useForm } from "react-hook-form";

function App() {
  const { register, watch, setValue, handleSubmit } = useForm({
    defaultValues: {
      firstName: "",
      lastName: ""
    }
  });
  const { firstName, lastName } = watch();

  useEffect(() => {
    register({ name: "firstName" });
    register({ name: "lastName" });
  }, [register]);

  const handleChange = (name, e) => {
    e.persist();
    setValue(name, e.target.value);
  };

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

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input
        onChange={handleChange.bind(null, "firstName")}
        value={firstName}
      />

      <input onChange={handleChange.bind(null, "lastName")} value={lastName} />
      <input type="submit" />
    </form>
  );
}

Testing React Hook Form

  • Why am I getting act warning?

    All validation methods in React Hook Form will be treated as async functions, so it's important to wrap async around your act.

  • Why input change is not fire event?

    React Hook Form using input event for input change, so to fix it. you can easily switch to fireEvent.input for react-testing-library


watch vs getValues vs state

  • watch: subscribe to input’s change via event listener and re-render based on which fields that are subscribed. Check out this codesandbox for actual behaviour.

  • getValues: get value which stored inside the custom hook as reference, fast and cheap. This method doesn’t trigger re-render.

  • local state: React local state represent more than just input’s state and also decide what to render. This will trigger on each input’s change.

We Need Your Support

If you find React Hook Form to be useful in your React project, please star to support the repo and contributors ❤