# subscribe

> Subscribe to React Hook Form state changes outside the render cycle — ideal for analytics, side effects, and non-React integrations.

Source: https://react-hook-form.com/docs/useform/subscribe

## `subscribe:` [UseFormSubscribe](https://react-hook-form.com/ts#UseFormSubscribe) _(since v7.55.0)_

Subscribe to [`formState`](https://react-hook-form.com/docs/useform/formstate) changes and value updates. You can subscribe to individual fields or the entire form, while avoiding unnecessary re-renders caused by form changes.

### Props

---

| Name      | Type                                          | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                   | Example                                                                                                                                                                                                                                                                  |
| --------- | --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| name      | `undefined`                | Subscribe to the entire form                                                                                                                                                                                                                                                                                                                                                                                                                                  | `subscribe({ callback })`                                                                                                                                                                                                                                                |
|           | `string`                   | Subscribe to a single field by **name**.                                                                                                                                                                                                                                                                                                                                                                                                                      | `subscribe({ name: 'firstName' })`                                                                                                                                                                                                                                       |
|           | `string[]`                 | Subscribe to multiple fields by **name**.                                                                                                                                                                                                                                                                                                                                                                                                                     | `subscribe({ name: ['firstName', 'lastName'] })`                                                                                                                                                                                                                         |
| formState | `Partial<ReadFormState>` | Pick which [`formState`](https://react-hook-form.com/docs/useform/formstate) to subscribe to.                                                                                                                                                                                                                                                                                                                                                                                            | <pre><code>subscribe({ <br/>  formState: { <br/>    values: true, <br/>    isDirty: true, <br/>    dirtyFields: true, <br/>    touchedFields: true, <br/>    isValid: true, <br/>    errors: true, <br/>    validatingFields: true, <br/>    isValidating: true <br/>  } <br/>})</code></pre> |
| callback  | `Function`               | Runs whenever any of the picked `formState` changes. It receives the full form state, plus `values` (the latest form values), `name` (the field that changed, if any) and `type` (the event, such as `change` or `blur`).                                                                                                                                                                                                                                     | <pre><code>subscribe({ <br/>  formState: { <br/>    values: true <br/>  }, <br/>  callback: ({ values }) =&gt; { <br/>    console.log(values) <br/>  } <br/>})</code></pre>                                                                                                          |
| exact     | `boolean = false`          | Enable exact name matching. When `false` (default), the subscription fires when the subscribed name is a prefix of the changed field name, or vice versa. _(since v7.81.0)_ When `true`, it fires when the subscribed field itself or one of its ancestor paths is updated, but not when a nested child path changes (for example, `"users.0.name"` is updated when `"users"` is set, while `"users"` is not updated when `"users.0.name"` changes). | `subscribe({ name: 'target', exact: true })`                                                                                                                                                                                                                             |

### Return

---

| Type                              | Description                                                                                                               |
| --------------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
| `() => void` | A function that ends the subscription. Call it when the component unmounts, for example by returning it from `useEffect`. |

> **Important: Notes**
>
> - This function shares the same functionality as `createFormControl.subscribe`, with the key difference being that [createFormControl](https://react-hook-form.com/docs/createFormControl) can be initialized outside of a React component.
> - This function is dedicated to subscribing to form state without **render**, use this function for that instead of [watch](https://react-hook-form.com/docs/useform/watch) callback function.
>

### Examples

---

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

type FormInputs = {
  firstName: string
  lastName: string
}

export default function App() {
  const { register, subscribe } = useForm<FormInputs>()

  useEffect(() => {
    // make sure to unsubscribe;
    const callback = subscribe({
      formState: {
        values: true,
      },
      callback: ({ values }) => {
        console.log(values)
      },
    })

    return () => callback()

    // You can also just return the subscribe
    // return subscribe({ callback: ({ values }) => console.log(values) });
  }, [subscribe])

  return (
    <form>
      <input {...register("firstName", { required: true })} />
      <input {...register("lastName", { required: true })} />
    </form>
  )
}
```

**Autosave a draft**

Because `subscribe` doesn't re-render, it suits side effects like saving a draft while the user types:

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

type FormValues = { title: string; body: string }

export default function App() {
  const { register, subscribe } = useForm<FormValues>({
    defaultValues: { title: "", body: "" },
  })

  useEffect(() => {
    let timer: ReturnType<typeof setTimeout>

    const unsubscribe = subscribe({
      formState: { values: true },
      callback: ({ values }) => {
        clearTimeout(timer)
        timer = setTimeout(() => {
          localStorage.setItem("draft", JSON.stringify(values))
        }, 500)
      },
    })

    return () => {
      clearTimeout(timer)
      unsubscribe()
    }
  }, [subscribe])

  return (
    <form>
      <input {...register("title")} />
      <textarea {...register("body")} />
    </form>
  )
}
```

### Tips

---

- Pick only the `formState` keys you need. The callback runs for each update to any of them, so a smaller selection means less work.
- Pass `name` to limit the subscription to one part of the form, such as `subscribe({ name: "shipping", ... })`.
- The callback can run on every key press. Debounce expensive work, such as saving to the server:

  ```javascript
  useEffect(() => {
    const save = debounce((values) => api.saveDraft(values), 500)
    const unsubscribe = subscribe({
      formState: { values: true },
      callback: ({ values }) => save(values),
    })
    return () => {
      unsubscribe()
      save.cancel()
    }
  }, [subscribe])
  ```

### Troubleshooting

---

#### The callback does not receive value changes

**Why it happens:**

`subscribe` only listens to the form-state properties selected in `formState`. Without `values: true`, changes to input values alone do not trigger a values subscription.

**Fix:**

Select values explicitly, and optionally limit the work to a field or section:

```javascript
return subscribe({
  name: "shipping",
  formState: { values: true },
  callback: ({ values }) => save(values.shipping),
})
```

#### The callback runs multiple times for one change

**Why it happens:**

A new subscription is being created on each render, or an effect creates one without removing the previous subscription.

**Fix:**

Create the subscription in an effect and return the unsubscribe function:

```javascript
useEffect(
  () =>
    subscribe({
      formState: { values: true },
      callback: ({ values }) => console.log(values),
    }),
  [subscribe]
)
```
