# useWatch

> Subscribe to input value changes with isolated component-level re-renders, offering better performance than watch for large React Hook Forms.

Source: https://react-hook-form.com/docs/usewatch

## `useWatch:` ([UseWatchProps](https://react-hook-form.com/ts#UseWatchProps)) => object

Behaves similarly to the `watch` API; however, it isolates re-rendering at the custom hook level, which can result in better performance for your application.

### Props

---

| Name           | Type                                                 | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| -------------- | ---------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `name`         | `string \| string[] \| undefined` | Name of the field. Reactive — changing this prop dynamically will update the subscription to the new field name.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| `control`      | `Object`                          | [`control`](https://react-hook-form.com/docs/useform/control) object provided by `useForm`. It's optional if you are using `FormProvider`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| `compute`      | `function`                        | <p>_(since v7.61.0)_ Subscribe to selective and computed form values.</p><ul><li>Subscribe to the entire form but only return updated value with certain condition<pre><code>const watchedValue = useWatch({<br/>  compute: (data: FormValue) =&gt; { <br/>    if (data.test?.length) return data.test; <br/><br/>    return ''; <br/>  }, <br/>});</code></pre></li><li>Subscribe to a specific form value state<pre><code>const watchedValue = useWatch({<br/>  name: 'test', <br/>  compute: (data: string) =&gt; { <br/>    return data.length ? data : ''; <br/>  }, <br/>});</code></pre></li></ul>                                              |
| `defaultValue` | `unknown`                         | Fallback value returned before the form has mounted and no current value exists yet. Once the form is mounted, the actual current form value takes precedence over this fallback.                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| `disabled`     | `boolean = false`                 | _(since v7.13.0)_ Option to disable the subscription.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| `exact`        | `boolean = false`                 | _(since v7.20.0)_ Enable exact name matching. When `false` (default), a subscription fires when the subscribed name is a prefix of the changed field name, or vice versa (for example, subscribing to `"users"` receives updates for `"users.0.name"`). _(since v7.81.0)_ When `true`, the subscription fires when the subscribed field itself or one of its ancestor paths is updated (for example, subscribing to `"users.0.name"` receives updates when `"users.0"` or `"users"` is set via `setValue`), but not when a nested child path changes (subscribing to `"users"` does not receive updates for `"users.0.name"`). |

### Return

---

| Example                              | Return                                         |
| ------------------------------------ | ---------------------------------------------- |
| `useWatch({ name: 'inputName' })`    | `unknown`                   |
| `useWatch({ name: ['inputName1'] })` | `unknown[]`                 |
| `useWatch()`                         | `{[key:string]: unknown}` |

> **Important: Rules**
>
> - On initial render, `useWatch` returns the current form value if available. The `defaultValue` prop (or `defaultValues` from `useForm`) is used only as a fallback before the form has mounted — i.e., before any values are registered.
> - The only difference between `useWatch` and `watch` is at the root ([`useForm`](https://react-hook-form.com/docs/useform)) level or the custom hook level.
> - Not sure whether to use `useWatch`, `watch`, `subscribe` or `getValues`? See [which API to use for reading values](https://react-hook-form.com/faqs#watchvsgetValuesvsstate).
> - `useWatch`'s execution order matters, which means if you update a form value before the subscription is in place, then the updated value will be ignored.
>
>   ```javascript
>   setValue("test", "data")
>   useWatch({ name: "test" }) // ❌ subscription happened after value update, no update received
>   useWatch({ name: "example" }) // ✅ input value update will be received and trigger re-render
>   setValue("example", "data")
>   ```
>
>   You can overcome the above issue with a simple custom hook as below:
>
>   ```javascript
>   const useFormValues = () => {
>     const { getValues } = useFormContext()
> 
>     return {
>       ...useWatch(), // subscribe to form value updates
> 
>       ...getValues(), // always merge with latest form values
>     }
>   }
>   ```
>
> - `useWatch`'s result is optimized for the render phase instead of `useEffect` dependencies. To detect value updates, you may want to use an external custom hook for value comparison.
>

### Examples

---

**Form**

**TS**

[Open in CodeSandbox](https://codesandbox.io/s/react-hook-form-v7-ts-usewatch-h9i5e)

```tsx
import { useForm, useWatch, Control } from "react-hook-form"

interface FormInputs {
  firstName: string
  lastName: string
}

function FirstNameWatched({ control }: { control: Control<FormInputs> }) {
  const firstName = useWatch({
    control,
    name: "firstName", // without supply name will watch the entire form, or ['firstName', 'lastName'] to watch both
    defaultValue: "default", // default value before the render
  })

  return <p>Watch: {firstName}</p> // only re-render at the custom hook level, when firstName changes
}

function App() {
  const { register, control, handleSubmit } = useForm<FormInputs>()

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

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <label>First Name:</label>
      <input {...register("firstName")} />
      <input {...register("lastName")} />
      <input type="submit" />

      <FirstNameWatched control={control} />
    </form>
  )
}
```

**JS**

[Open in CodeSandbox](https://codesandbox.io/s/react-hook-form-v7-usewatch-forked-9872t)

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

function Child({ control }) {
  const firstName = useWatch({
    control,
    name: "firstName",
  })

  return <p>Watch: {firstName}</p>
}

function App() {
  const { register, control } = useForm({
    defaultValues: {
      firstName: "test",
    },
  })

  return (
    <form>
      <input {...register("firstName")} />
      <Child control={control} />
    </form>
  )
}
```

**Advanced Field Array**

[Open in CodeSandbox](https://codesandbox.io/s/watchusewatch-calc-4tpnh)

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

function totalCal(results) {
  let totalValue = 0

  for (const key in results) {
    for (const value in results[key]) {
      if (typeof results[key][value] === "string") {
        const output = parseInt(results[key][value], 10)
        totalValue = totalValue + (Number.isNaN(output) ? 0 : output)
      } else {
        totalValue = totalValue + totalCal(results[key][value], totalValue)
      }
    }
  }

  return totalValue
}

export const Calc = ({ control, setValue }) => {
  const results = useWatch({ control, name: "test" })
  const output = totalCal(results)

  // isolated re-render to calc the result with Field Array
  console.log(results)

  setValue("total", output)

  return <p>{output}</p>
}
```

### Tips

---

- Use `compute` to derive a small value from the form. The component re-renders only when the computed result changes (compared deeply), not on every key press:

  ```javascript
  const isAdult = useWatch({
    control,
    name: "age",
    compute: (age) => Number(age) >= 18,
  })
  ```

- For totals in a field array, watch the array in a small child component, so typing in one row does not re-render the whole list:

  ```javascript
  function Total({ control }) {
    const total = useWatch({
      control,
      name: "items",
      compute: (items = []) =>
        items.reduce((sum, item) => sum + Number(item.price || 0), 0),
    })
    return <p>Total: {total}</p>
  }
  ```

- Pass `name` to watch only what you need. `useWatch()` with no `name` watches the whole form.

### Troubleshooting

---

#### `useWatch` returns `undefined` on the first render

**Why it happens:**

`useWatch` runs before the input registers, so on the first render it returns the field's default value. With no default value, that is `undefined`.

**Fix:**

Set the field in `defaultValues` on `useForm`, or pass `defaultValue` to `useWatch`.

#### `Cannot read properties of null (reading '_getWatch')`

**Why it happens:**

`useWatch` could not find a form: no `control` was passed and the component is not inside a [`FormProvider`](https://react-hook-form.com/docs/formprovider).

**Fix:**

Pass `control` from `useForm`, or wrap the tree in `<FormProvider {...methods}>`.
