Skip to content

useWatch

React Hook for subscribe to input changes

useWatch: ({ control?: Control, name?: string, defaultValue?: any }) => object

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

Props

NameTypeDescription
namestring | string[]Name of the field.
controlObjectcontrol object provided by useForm. It's optional if you are using FormContext.
defaultValueany

default value for useWatch to return before the initial render.

Note: the first render will always return defaultValue when it's supplied.

disableboolean = false

Option to disable the subscription.

Rules

  • The initial return value from useWatch will always return what's inside of defaultValue or defaultValues from useForm.

  • The only different between useWatch and watch is at root level or component level update.

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

    setValue('test', 'data');
    useWatch('test'); // ❌ subscription is happened after value update, no update received
    
    useWatch('example'); // ✅ input value update will be received and trigger re-render
    setValue('example', 'data'); 
    
  • useWatch result is optimised for render phase instead of useEffect's deps, to detect value update you may want to use an external custom hook for value comparison.

import React from "react";
import { useForm, useWatch } from "react-hook-form";

function IsolateReRender({ control }) {
  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 <div>{firstName}</div>; // only re-render at the component level, when firstName changes
}

function App() {
  const { register, control, handleSubmit } = useForm();
  
  return (
    <form onSubmit={handleSubmit(data => console.log("data", data))}>
      <input {...register("firstName")} />
      <input {...register("last")} />
      <IsolateReRender control={control} />
      
      <input type="submit" />
    </form>
  );
}
import React from "react";
import { useForm, useWatch } from "react-hook-form";

interface FormInputs {
  firstName: 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 component 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 type="submit" />
      <FirstNameWatched control={control} />
    </form>
  );
}
import React from "react";
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>;
};

Edit