Capítulo 35 de 39

Chapter 35: useWatch

Core Idea

useWatch({ control, name?, compute?, defaultValue?, exact? }) is watch's isolated-re-render sibling — call it inside a small child component and only that component re-renders when the watched value changes, instead of the whole form-holding component.

Key Concepts

  • name: reactive — a single name, an array, or omitted (watches everything); changing it dynamically re-subscribes.
  • compute (7.61.0+): a selector function to subscribe to a derived/filtered value instead of the raw field value, cutting re-renders further (e.g. return '' unless a condition is met).
  • defaultValue: fallback used only before the form mounts (no current value registered yet) — once mounted, the actual value always wins over this fallback.
  • exact: defaults false — a subscription to "users" also fires on changes to "users.0.name" (prefix match); set true to require an exact name match.
  • Subscription-order sensitivity: useWatch only sees updates that happen after its subscription is set up — calling setValue before a given useWatch call runs means that specific update is missed by that watcher, even though the underlying value did change. A useFormValues custom hook that spreads ...useWatch() then ...getValues() (getValues last, so it overrides with the latest) sidesteps this for a "give me the freshest snapshot" use case.
  • Not for useEffect dependencies: useWatch's return is optimized for the render phase; use a separate value-comparison hook if you need to react to changes outside render.

Code Examples

function FirstNameWatched({ control }) {
  const firstName = useWatch({ control, name: "firstName", defaultValue: "default" })
  return <p>Watch: {firstName}</p> // only this component re-renders on change
}
  • What it demonstrates: isolating a watched value's re-render to a small child component instead of the form root.
export const Calc = ({ control, setValue }) => {
  const results = useWatch({ control, name: "test" }) // "test" is a field array
  const output = totalCal(results) // sum quantities/prices recursively
  setValue("total", output)
  return <p>{output}</p>
}
  • What it demonstrates: deriving a computed total from a field array's live values, a common useFieldArray + useWatch pairing.

Reference Tables

CallReturn type
useWatch({ name: 'field' })unknown
useWatch({ name: ['a','b'] })unknown[]
useWatch(){ [key: string]: unknown }

Anti-patterns

  • Calling setValue before the relevant useWatch subscription exists: that specific update is silently missed by that watcher — order matters.
  • Using useWatch's return value inside a useEffect dependency array expecting change detection semantics: it's render-phase optimized, not effect-phase; use a dedicated comparison hook instead.
  • Watching the entire form (useWatch() with no name) in a large form just to read one field: defeats the isolation purpose — scope name (and compute) as tightly as possible.

Key Takeaways

  1. useWatch == watch, but scoped to its own hook/component for re-render isolation — prefer it over watch in components that don't need the full form.
  2. compute (7.61.0+) lets you subscribe to a derived value instead of the raw field, reducing re-renders even further.
  3. Subscription timing matters: a watcher only sees updates fired after it was set up.

Connects To

  • useform-watch: the root-level, non-isolated equivalent.
  • usefieldarray: useWatch is the standard way to compute totals/derived state from array-field values.
  • usewatch-watch: the declarative <Watch> component built on this hook.