From d168c9f72e4eae7597dd22e6272ed052527e30c7 Mon Sep 17 00:00:00 2001 From: 22mb <249426134+22mb@users.noreply.github.com> Date: Sat, 29 Aug 2026 13:28:09 +0900 Subject: [PATCH] docs: document exact ancestor-path matching since 7.81.0 Since react-hook-form 7.81.0 (react-hook-form/react-hook-form#13553), subscriptions with `exact: true` also fire when an ancestor path of the subscribed name is updated. Changes to nested child paths still do not notify with `exact: true`. Update the `exact` row in the useWatch, useFormState, useController, Controller, Watch, FormState and subscribe props tables accordingly, and show subscribe's default (`boolean = false`). --- src/content/docs/usecontroller.mdx | 18 +++++++++--------- src/content/docs/usecontroller/controller.mdx | 2 +- src/content/docs/useform/subscribe.mdx | 16 ++++++++-------- src/content/docs/useformstate.mdx | 12 ++++++------ src/content/docs/useformstate/formstate.mdx | 14 +++++++------- src/content/docs/usewatch.mdx | 16 ++++++++-------- src/content/docs/usewatch/watch.mdx | 2 +- 7 files changed, 40 insertions(+), 40 deletions(-) diff --git a/src/content/docs/usecontroller.mdx b/src/content/docs/usecontroller.mdx index a38611da0..482084f04 100644 --- a/src/content/docs/usecontroller.mdx +++ b/src/content/docs/usecontroller.mdx @@ -24,15 +24,15 @@ This custom hook powers [`Controller`](/docs/usecontroller/controller). Addition The following table contains information about the arguments for `useController`. -| Name | Type | Required | Description | -| ------------------ | ----------------------------------------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `name` | [FieldPath](/ts#FieldPath) | ✓ | Unique name of your input. Reactive — the controller re-subscribes when this prop changes, allowing dynamic field name switching. | -| `control` | [Control](/ts#Control) | | [`control`](/docs/useform/control) object provided by invoking `useForm`. Optional when using `FormProvider`. | -| `rules` | Object | | Validation rules in the same format for `register`, which includes: `required`, `min`, `max`, `minLength`, `maxLength`, `pattern`, `validate`.

`rules={{ required: true }}` | -| `shouldUnregister` | boolean = false | | Input will be unregistered after unmount and defaultValues will be removed as well. **Note:** this prop should be avoided when using with `useFieldArray` as `unregister` function gets called after input unmount/remount and reorder. | -| `disabled` | boolean = false | | `disabled` prop will be returned from `field` prop. Controlled input will be disabled and its value will be omitted from the submission data. | -| `defaultValue` | unknown | | **Important:** Cannot apply `undefined` to `defaultValue` or `defaultValues` at `useForm`. | -| `exact` | boolean = true | | This prop will enable an exact match for input name subscriptions, default to true. **Note:** this differs from [`useWatch`](/docs/usewatch) and [`useFormState`](/docs/useformstate), which both default `exact` to `false`. | +| Name | Type | Required | Description | +| ------------------ | ----------------------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `name` | [FieldPath](/ts#FieldPath) | ✓ | Unique name of your input. Reactive — the controller re-subscribes when this prop changes, allowing dynamic field name switching. | +| `control` | [Control](/ts#Control) | | [`control`](/docs/useform/control) object provided by invoking `useForm`. Optional when using `FormProvider`. | +| `rules` | Object | | Validation rules in the same format for `register`, which includes: `required`, `min`, `max`, `minLength`, `maxLength`, `pattern`, `validate`.

`rules={{ required: true }}` | +| `shouldUnregister` | boolean = false | | Input will be unregistered after unmount and defaultValues will be removed as well. **Note:** this prop should be avoided when using with `useFieldArray` as `unregister` function gets called after input unmount/remount and reorder. | +| `disabled` | boolean = false | | `disabled` prop will be returned from `field` prop. Controlled input will be disabled and its value will be omitted from the submission data. | +| `defaultValue` | unknown | | **Important:** Cannot apply `undefined` to `defaultValue` or `defaultValues` at `useForm`.
  • You need to either set `defaultValue` at the field-level or `useForm`'s `defaultValues`. `undefined` is not a valid value. If you used `defaultValues` at `useForm`, skip using this prop.
  • If your form will invoke `reset` with default values, you will need to provide `useForm` with `defaultValues`.
  • If `field.value` is `undefined` on first render, the input starts out uncontrolled and React will warn when it later becomes controlled — always set `defaultValue`/`defaultValues` to avoid this.
| +| `exact` | boolean = true | | This prop will enable an exact match for input name subscriptions, default to true. With `exact: true`, the field is also updated when one of its ancestor paths is set (for example, a field named `"users.0.name"` reflects `setValue("users.0", { name: "Jane" })`), but not when a nested child path of its value changes (for example, `setValue("users.0.name", "Jane")` does not update a field named `"users.0"`). Pass `exact: false` to also receive nested updates. **Note:** this differs from [`useWatch`](/docs/usewatch) and [`useFormState`](/docs/useformstate), which both default `exact` to `false`. | ### Return diff --git a/src/content/docs/usecontroller/controller.mdx b/src/content/docs/usecontroller/controller.mdx index 86d5de9db..d2624237f 100644 --- a/src/content/docs/usecontroller/controller.mdx +++ b/src/content/docs/usecontroller/controller.mdx @@ -26,7 +26,7 @@ The following table contains information about the arguments for `Controller`. | `shouldUnregister` | boolean = false | | Input will be unregistered after unmount and defaultValues will be removed as well.

**Note:** this prop should be avoided when using with `useFieldArray` as `unregister` function gets called after input unmount/remount and reorder. | | `disabled` | boolean = false | | `disabled` prop will be returned from `field` prop. Controlled input will be disabled and its value will be omitted from the submission data. | | `defaultValue` | unknown | | **Important:** Cannot apply `undefined` to `defaultValue` or `defaultValues` at `useForm`.
  • You need to either set `defaultValue` at the field level or `useForm`'s `defaultValues`. If you used defaultValues at useForm, skip using this prop.
  • If your form will invoke `reset` with default values, you will need to provide `useForm` with `defaultValues`.
  • Calling `onChange` with `undefined` is not valid. You should use `null` or the empty string as your default/cleared value instead.
  • If `field.value` is `undefined` on first render, the input starts out uncontrolled and React will warn when it later becomes controlled — always set `defaultValue`/`defaultValues` to avoid this.
| -| `exact` | boolean = true | | This prop will enable an exact match for input name subscriptions, default to true. | +| `exact` | boolean = true | | This prop will enable an exact match for input name subscriptions, default to true. With `exact: true`, the field is also updated when one of its ancestor paths is set, but not when a nested child path of its value changes. See [`useController`](/docs/usecontroller) for details. | ### Return diff --git a/src/content/docs/useform/subscribe.mdx b/src/content/docs/useform/subscribe.mdx index d544e5e85..84bed1c2b 100644 --- a/src/content/docs/useform/subscribe.mdx +++ b/src/content/docs/useform/subscribe.mdx @@ -13,14 +13,14 @@ Subscribe to [`formState`](/docs/useform/formstate) changes and value updates. Y --- -| Name | Type | Description | Example | -| --------- | --------------------------------------------- | ------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| name | undefined | Subscribe to the entire form | `subscribe()` | -| | string | Subscribe to a single field by **name**. | `subscribe({ name: 'firstName' })` | -| | string[] | Subscribe to multiple fields by **name**. | `subscribe({ name: ['firstName', 'lastName'] })` | -| formState | `Partial` | Pick which [`formState`](/docs/useform/formstate) to subscribe to. | | -| callback | `Function` | The callback function for the subscription. | { \n console.log(values) \n } \n})`}/> | -| exact | boolean | This prop will enable an exact match for input name subscriptions. | `subscribe({ name: 'target', exact: true })` | +| Name | Type | Description | Example | +| --------- | --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| name | undefined | Subscribe to the entire form | `subscribe()` | +| | string | Subscribe to a single field by **name**. | `subscribe({ name: 'firstName' })` | +| | string[] | Subscribe to multiple fields by **name**. | `subscribe({ name: ['firstName', 'lastName'] })` | +| formState | `Partial` | Pick which [`formState`](/docs/useform/formstate) to subscribe to. | | +| callback | `Function` | The callback function for the subscription. | { \n console.log(values) \n } \n})`}/> | +| 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. 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 })` | diff --git a/src/content/docs/useformstate.mdx b/src/content/docs/useformstate.mdx index 160361307..0e46140b3 100644 --- a/src/content/docs/useformstate.mdx +++ b/src/content/docs/useformstate.mdx @@ -26,12 +26,12 @@ This custom hook allows you to subscribe to each form state, and isolate re-rend --- -| Name | Type | Description | -| ---------- | ---------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | -| `control` | Object | [`control`](/docs/useform/control) object provided by `useForm`. It's optional if you are using `FormProvider`. | -| `name` | string \| string[] | Provide a single input name, an array of them, or subscribe to all inputs' formState updates. | -| `disabled` | boolean = false | Option to disable the subscription. | -| `exact` | boolean = false | This prop will enable an exact match for input name subscriptions. | +| Name | Type | Description | +| ---------- | ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `control` | Object | [`control`](/docs/useform/control) object provided by `useForm`. It's optional if you are using `FormProvider`. | +| `name` | string \| string[] | Provide a single input name, an array of them, or subscribe to all inputs' formState updates. | +| `disabled` | boolean = false | Option to disable the subscription. | +| `exact` | boolean = false | 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"`). 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 diff --git a/src/content/docs/useformstate/formstate.mdx b/src/content/docs/useformstate/formstate.mdx index edea8cedd..2ac691346 100644 --- a/src/content/docs/useformstate/formstate.mdx +++ b/src/content/docs/useformstate/formstate.mdx @@ -13,13 +13,13 @@ A React Hook Form component that provides the same functionality as `useFormStat --- -| Name | Type | Description | -| ---------- | ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `control` | Object | [`control`](/docs/useform/control) object provided by `useForm`. It's optional if you are using `FormProvider`. | -| `name` | string \| string[] | Provide a single input name, an array of them, or subscribe to all inputs' formState update. | -| `disabled` | boolean = false | Option to disable the subscription. | -| `exact` | boolean = false | This prop will enable an exact match for input name subscriptions. | -| `render` | Function | Subscribes to form state of specified form field(s) and re-renders its child function whenever the form state changes. This allows you to declaratively consume form state in JSX without manually wiring up state. | +| Name | Type | Description | +| ---------- | ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `control` | Object | [`control`](/docs/useform/control) object provided by `useForm`. It's optional if you are using `FormProvider`. | +| `name` | string \| string[] | Provide a single input name, an array of them, or subscribe to all inputs' formState update. | +| `disabled` | boolean = false | Option to disable the subscription. | +| `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. 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. See [`useFormState`](/docs/useformstate) for details. | +| `render` | Function | Subscribes to form state of specified form field(s) and re-renders its child function whenever the form state changes. This allows you to declaratively consume form state in JSX without manually wiring up state. | diff --git a/src/content/docs/usewatch.mdx b/src/content/docs/usewatch.mdx index f6e1798de..f8b459c7b 100644 --- a/src/content/docs/usewatch.mdx +++ b/src/content/docs/usewatch.mdx @@ -22,14 +22,14 @@ Behaves similarly to the `watch` API; however, it isolates re-rendering at the c --- -| 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`](/docs/useform/control) object provided by `useForm`. It's optional if you are using `FormProvider`. | -| `compute` | function |

Subscribe to selective and computed form values.

  • Subscribe to the entire form but only return updated value with certain condition { \n if (data.test?.length) return data.test; \n\n return ''; \n }, \n});`}/>
  • Subscribe to a specific form value state { \n return data.length ? data : ''; \n }, \n});`}/>
| -| `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 | Option to disable the subscription. | -| `exact` | boolean = false | 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"`). | +| 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`](/docs/useform/control) object provided by `useForm`. It's optional if you are using `FormProvider`. | +| `compute` | function |

Subscribe to selective and computed form values.

  • Subscribe to the entire form but only return updated value with certain condition { \n if (data.test?.length) return data.test; \n\n return ''; \n }, \n});`}/>
  • Subscribe to a specific form value state { \n return data.length ? data : ''; \n }, \n});`}/>
| +| `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 | Option to disable the subscription. | +| `exact` | boolean = false | 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"`). 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 diff --git a/src/content/docs/usewatch/watch.mdx b/src/content/docs/usewatch/watch.mdx index 216ee79fb..dfb4f75fd 100644 --- a/src/content/docs/usewatch/watch.mdx +++ b/src/content/docs/usewatch/watch.mdx @@ -20,7 +20,7 @@ A React Hook Form component that provides the same functionality as `useWatch`, | `compute` | function |

Subscribe to selective and computed form values.

  • Subscribe to the entire form but only return updated value with certain condition { \n if (data.test?.length) return data.test; \n\n return ''; \n }, \n});`}/>
  • Subscribe to a specific form value state { \n return data.length ? data : ''; \n }, \n});`}/>
| | `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 | Option to disable the subscription. | -| `exact` | boolean = false | This prop will enable an exact match for input name subscriptions. | +| `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. 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. See [`useWatch`](/docs/usewatch) for details. | | `render` | Function | Subscribes to specified form field(s) and re-renders its child function whenever the values change. This allows you to declaratively consume form values in JSX without manually wiring up state. | ##### Examples: