# FAQs

> Frequently asked questions

Source: https://react-hook-form.com/faqs

## Performance of React Hook Form

Performance is one of the primary reasons why this library was created. React Hook Form relies on an uncontrolled form, which is why the `register` function captures a `ref` directly instead of `value`/`onChange`. For components that must stay controlled, `Controller` or `useController` isolate re-renders to just that field instead of the whole form. This approach reduces the number of re-renders that occur due to a user typing in an input or other form values changing at the root of your form or applications. Components mount to the page faster than controlled components because they have less overhead. As a reference, there is a quick comparison test that you can refer to at [this repo link](https://github.com/bluebill1049/react-hook-form-performance-compare).

---

## How to create an accessible input error and message?

React Hook Form is based on Uncontrolled Components, which gives you the ability to build an accessible custom form easily.
_(For more information about Uncontrolled Components, read [Sharing State Between Components](https://react.dev/learn/sharing-state-between-components))_. See also React's guide on [controlled and uncontrolled inputs](https://react.dev/reference/react-dom/components/input#controlling-an-input-with-a-state-variable).

```javascript
import { useForm } from "react-hook-form"

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

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <label htmlFor="firstName">First name</label>
      <input
        id="firstName"
        aria-invalid={errors.firstName ? "true" : "false"}
        {...register("firstName", { required: true })}
      />
      {errors.firstName && <span role="alert">This field is required</span>}

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

---

## Does it work with Class Components?

No, not out of the box. If you want to do this, you can build a wrapper around it and use it 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 simply an implementation detail of that component. In the longer term, we expect Hooks to be the primary way people write React components.

---

## Does it work with React's `<Activity />` component?

_(since v7.85.0)_ Yes. Hiding a form with `<Activity mode="hidden">`
unmounts its effects and subscriptions, then remounts them when it becomes
visible again, which used to leave `useWatch` values and
`formState.isSubmitting` stale after restoration. React Hook Form now
resyncs its internal subscriptions on remount, so state stays correct across
`<Activity />` visibility changes without any extra configuration.

---

## 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. It only clears `input/select/checkbox` values.

- **React Hook Form API: `reset()`**

  React Hook Form's `reset` method will reset all field values, and will also clear all `errors` within the form.

---

## How to initialize form values?

Being that React Hook Form relies on an uncontrolled form, you can specify a `defaultValue` or `defaultChecked` to an individual field. However, it is more common and recommended to initialize a form by passing `defaultValues` to `useForm`.

```javascript
function App() {
  const { register, handleSubmit } = useForm({
    defaultValues: {
      firstName: "bill",
      lastName: "luo",
    },
  })

  return (
    <form onSubmit={handleSubmit((data) => console.log(data))}>
      <input {...register("firstName")} />
      <input {...register("lastName")} />
      <button type="submit">Submit</button>
    </form>
  )
}
```

For async default values, you can use the following methods:

- Async `defaultValues`

  ```javascript
  function App() {
    const { register, handleSubmit } = useForm({
      defaultValues: async () => {
        const response = await fetch("/api")
        return await response.json() // return { firstName: '', lastName: '' }
      },
    })
  }
  ```

- Reactive `values`

  ```javascript
  function App() {
    const { data } = useQuery() // data returns { firstName: '', lastName: '' }
    const { register, handleSubmit } = useForm({
      values: data,
      resetOptions: {
        keepDirtyValues: true, // keep dirty fields unchanged, but update defaultValues
      },
    })
  }
  ```

---

## How to share ref usage?

React Hook Form needs a `ref` to collect the input value. However, you may want to use `ref` for other purposes (e.g. scroll into view, or focus).

**TS**

```tsx
import { useRef } from "react"
import { useForm } from "react-hook-form"

type Inputs = {
  firstName: string
  lastName: string
}

export default function App() {
  const { register, handleSubmit } = useForm<Inputs>()
  const firstNameRef = useRef<HTMLInputElement | null>(null)
  const onSubmit = (data: Inputs) => console.log(data)
  const { ref, ...rest } = register("firstName")
  const onClick = () => {
    if (firstNameRef.current) firstNameRef.current.value = ""
  }

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input
        {...rest}
        ref={(e) => {
          ref(e) // pass the element to RHF
          firstNameRef.current = e // keep your own reference
        }}
      />
      <button type="button" onClick={onClick}>
        clear
      </button>
      <button>Submit</button>
    </form>
  )
}
```

**JS**

```javascript
import { useRef } from "react"
import { useForm } from "react-hook-form"

export default function App() {
  const { register, handleSubmit } = useForm()
  const firstNameRef = useRef(null)
  const onSubmit = (data) => console.log(data)
  const { ref, ...rest } = register("firstName")
  const onClick = () => {
    if (firstNameRef.current) firstNameRef.current.value = ""
  }

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input
        {...rest}
        ref={(e) => {
          ref(e) // pass the element to RHF
          firstNameRef.current = e // keep your own reference
        }}
      />
      <button type="button" onClick={onClick}>
        clear
      </button>
      <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 `trigger`.

**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 the value and error.

```javascript
import { useEffect } from "react"
import { useForm } from "react-hook-form"

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

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

  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", { type: "notMatch" })
          } else {
            setValue("lastName", e.target.value)
          }
        }}
      />
      <button>Submit</button>
    </form>
  )
}
```

---

## Why is the first keystroke not working?

Make sure you are not using `value`. The correct property is `defaultValue`.

React Hook Form focuses on uncontrolled inputs, which means you don't need to change the input `value` via `state` via `onChange`. In fact, you don't need `value` at all. You only need to set `defaultValue` for the initial input value.

---

## React Hook Form, Formik or Redux Form?

First of all, all libs try to solve the same problem: making the form building experience as easy as possible. However, there are some fundamental differences between these three. `react-hook-form` is built with uncontrolled inputs in mind and tries to provide your form with the best performance and the minimum number of re-renders possible. Additionally, `react-hook-form` is built with React Hooks and used as a hook, which means there is no component to import. Here are some of the detailed differences:

|                    | React Hook Form                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 | Formik                                                                                        | Redux Form                                                                                      |
| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- |
| **Component**      | [uncontrolled](https://react.dev/reference/react-dom/components/input#controlling-an-input-with-a-state-variable) & [controlled](https://react.dev/learn/sharing-state-between-components)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      | [controlled](https://react.dev/learn/sharing-state-between-components)                        | [controlled](https://react.dev/learn/sharing-state-between-components)                          |
| **Rendering**      | minimal re-renders and optimized computation                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    | re-render according to local state changes (As you type in the input.)                        | re-render according to state management lib (Redux) changes (As you type in the input.)         |
| **API**            | Hooks                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           | Component (RenderProps, Form, Field) + Hooks                                                  | Component (RenderProps, Form, Field)                                                            |
| **Package size**   | Small <br/> Check the latest size on [Bundlephobia](https://bundlephobia.com/package/react-hook-form)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           | Medium <br />Check the latest size on [Bundlephobia](https://bundlephobia.com/package/formik) | Large <br/>Check the latest size on [Bundlephobia](https://bundlephobia.com/package/redux-form) |
| **Validation**     | Built-in <br/> [Yup](https://github.com/jquense/yup) <br/> [Zod](https://github.com/colinhacks/zod) <br/> [Superstruct](https://github.com/ianstormtaylor/superstruct) <br/> [Joi](https://github.com/sideway/joi) <br/> [Vest](https://github.com/ealush/vest) <br/> [Class Validator](https://github.com/typestack/class-validator) <br/> [io-ts](https://github.com/gcanti/io-ts) <br/> [Nope](https://github.com/bvego/nope-validator) <br/> [computed-types](https://github.com/neuledge/computed-types) <br/> [typanion](https://github.com/arcanis/typanion) <br/> [Ajv](https://github.com/ajv-validator/ajv) <br/> [TypeBox](https://github.com/sinclairzx81/typebox) <br/> [ArkType](https://github.com/arktypeio/arktype) <br/> [Valibot](https://valibot.dev/) <br/> [TypeSchema](https://typeschema.com) <br/> [effect-ts](https://github.com/Effect-TS/effect) <br/> [VineJS](https://github.com/vinejs/vine) <br/> [fluentvalidation-ts](https://github.com/AlexJPotter/fluentvalidation-ts) <br/> [ata-validator](https://github.com/nicholasgasior/ata-validator) <br/> [Standard Schema](https://standardschema.dev/) <br/> or build your own | Build yourself or [Yup](https://github.com/jquense/yup)                                       | Build yourself or Plugins                                                                       |
| **Learning curve** | Low to Medium                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   | Medium                                                                                        | Medium                                                                                          |

---

## watch vs getValues vs state

React Hook Form offers several ways to read form values. They differ in what re-renders when a value changes:

| API                                                                           | Re-renders                         | Use it for                                                                                                                               |
| ----------------------------------------------------------------------------- | ---------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| [`watch`](https://react-hook-form.com/docs/useform/watch)                                                | The component that calls `useForm` | Rendering a value at the form level. Simple, but every watched change re-renders the whole form.                                         |
| [`useWatch`](https://react-hook-form.com/docs/usewatch)                                                  | Only the component that calls it   | Rendering a value deep in the tree, such as a live total or a conditional field. Usually the best choice for performance.                |
| [`subscribe`](https://react-hook-form.com/docs/useform/subscribe)                                        | Nothing                            | Side effects such as autosave, analytics or syncing to external state.                                                                   |
| [`getValues`](https://react-hook-form.com/docs/useform/getvalues)                                        | Nothing                            | Reading the latest values on demand, for example in an event handler. It doesn't subscribe to changes, so don't use it to render values. |
| [`useFormState`](https://react-hook-form.com/docs/useformstate) / [`formState`](https://react-hook-form.com/docs/useform/formstate) | When the state you read changes    | Form state such as `errors`, `isDirty` or `isSubmitting`, not field values.                                                              |
| Local React state                                                             | Every change you store in it       | Values that also drive UI outside the form. Avoid mirroring every input into state.                                                      |

> **Important: React Compiler**
>
> `watch` and `getValues` keep the same reference across renders, so the [React Compiler](https://react.dev/learn/react-compiler) may cache what they return and render stale values. In compiled components, use `useWatch` to render values and `subscribe` for side effects, or opt the component out with the `"use no memo"` directive. v8 adds React Compiler support; see the [migration guide](https://react-hook-form.com/migrate-v7-to-v8#ReactCompiler).
>

---

## Why is default value not changing correctly with ternary operator?

React Hook Form doesn't control your entire form and inputs, which is why React doesn't recognize that the actual input has been exchanged or swapped. As a solution, you can resolve this problem by giving a unique `key` prop to your input. You can also read more about the key props from [this article written by Kent C. Dodds](https://kentcdodds.com/blog/understanding-reacts-key-prop).

[Open in CodeSandbox](https://codesandbox.io/s/react-hook-form-faq-toggle-fields-3htr6)

```javascript
import { useForm } from "react-hook-form"

export default function App() {
  const { register, watch } = useForm()
  const watchChecked = watch("checkbox")

  return (
    <div>
      <input type="checkbox" {...register("checkbox")} />
      {watchChecked ? (
        <input {...register("input3")} key="key1" defaultValue="1" />
      ) : (
        <input {...register("input4")} key="key2" defaultValue="2" />
      )}
    </div>
  )
}
```

---

## How to work with modal or tab forms?

It's important to understand that React Hook Form embraces native form behavior by storing input state inside each input (except custom `register` at `useEffect`). A common misconception is that input state remains with mounted or unmounted inputs. This is common when working with modal or tab forms. Instead, the correct solution is to build a new form for your form inside each modal or tab and capture your submission data in local or global state and then do something with the combined data.

- [Modal form and toggle inputs example](https://codesandbox.io/s/react-hook-form-modal-form-conditional-inputs-c7n0r)
- [Tab form example](https://codesandbox.io/s/tabs-760h9)

Alternatively, you can use `shouldUnregister: false` (the default) when calling `useForm`.

**Controller**

```javascript
import { useForm, Controller } from "react-hook-form"

function App() {
  const { control } = useForm()

  return (
    <Controller
      render={({ field }) => <input {...field} />}
      name="firstName"
      control={control}
      defaultValue=""
    />
  )
}
```

**Custom Register**

[Open in CodeSandbox](https://codesandbox.io/s/react-hook-form-controlled-input-forked-rl2v1)

```javascript
import { 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("firstName")
    register("lastName")
  }, [register])

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

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

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

      <input onChange={(e) => handleChange(e, "lastName")} value={lastName} />
      <input type="submit" />
    </form>
  )
}
```
