Skip to content

useWatch

Subscribe to input changes with isolated component re-renders.

</> useWatch: (UseWatchProps) => object

Behaves similarly to the watch API, however, this will isolate re-rendering at the custom hook level and potentially result in better performance for your application.

Props


NameTypeDescription
namestring | string[] | undefinedName of the field. Reactive — changing this prop dynamically will update the subscription to the new field name.
controlObjectcontrol object provided by useForm. It's optional if you are using FormProvider.
computefunction

Subscribe to selective and computed form values.

  • Subscribe to the entire form but only return updated value with certain condition
    const watchedValue = useWatch({
    compute: (data: FormValue) => {
    if (data.test?.length) return data.test;
    return '';
    },
    });
  • Subscribe to a specific form value state
    const watchedValue = useWatch({
    name: 'test',
    compute: (data: string) => {
    return data.length ? data : '';
    },
    });
defaultValueunknownFallback 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.
disabledboolean = falseOption to disable the subscription.
exactboolean = falseEnable 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").

Return


ExampleReturn
useWatch({ name: 'inputName' })unknown
useWatch({ name: ['inputName1'] })unknown[]
useWatch(){[key:string]: unknown}
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) level or the custom hook level update.

  • useWatch's execution order matters, which means if you update a form value before the subscription is in place, then the value updated will be ignored.

    setValue("test", "data")
    useWatch({ name: "test" }) // ❌ subscription is 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:

    const useFormValues = () => {
    const { getValues } = useFormContext()
    return {
    ...useWatch(), // subscribe to form value updates
    ...getValues(), // always merge with latest form values
    }
    }
  • useWatch's result is optimised for render phase instead of useEffect's deps, to detect value updates you may want to use an external custom hook for value comparison.

Examples:

Form

import { useForm, useWatch } 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>
)
}
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

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>
}

Thank you for your support

If you find React Hook Form to be useful in your project, please consider to star and support it.

Edit