If you've recently upgraded to React 19 and found that your React Hook Form components aren't re-rendering when form values change, you're not alone. This is a common issue that has caught many developers by surprise, especially when using the watch API.
The Problem
You have a form built with React Hook Form, and you're using the watch method to track changes to form values. Your code might look something like this:
jsx
functionMyFormComponent() {
const methods = useForm({
defaultValues: initialData
});
// Using watch to observe form valuesconst someFormValue = methods.watch("someField");
// Render UI based on watched valuereturn (
<FormProvider {...methods}><formonSubmit={methods.handleSubmit(onSubmit)}>
{/* Form fields */}
{/* Conditional rendering based on watched value */}
{someFormValue && <SomeConditionalComponent />}
</form></FormProvider>
);
}
But in React 19, you've noticed that when someFormValue changes, your component doesn't re-render to show or hide SomeConditionalComponent. This is frustrating because:
Your form values are actually updating correctly (you can verify this by logging or by forcing a re-render)
This same code worked perfectly in React 18 or earlier
The Cause
With React 19's changes to the rendering model, React Hook Form's watch method no longer triggers component re-renders as reliably as before. This is because:
React 19 implements more aggressive batching of updates
React Hook Form's watch is optimized for access to form values but not necessarily for triggering re-renders
The Solution: useWatch
The solution is simple but not immediately obvious: use useWatch instead of watch for values that need to trigger UI updates.
According to the React Hook Form documentation:
[useWatch] 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.
Here's how to refactor your code:
jsx
import { useForm, useWatch, FormProvider } from"react-hook-form";
functionMyFormComponent() {
const methods = useForm({
defaultValues: initialData
});
// Using useWatch instead of watchconst someFormValue = useWatch({
control: methods.control,
name: "someField",
defaultValue: initialData.someField// Optional, but recommended
});
// Now your component will re-render when someFormValue changesreturn (
<FormProvider {...methods}><formonSubmit={methods.handleSubmit(onSubmit)}>
{/* Form fields */}
{/* This will now work as expected */}
{someFormValue && <SomeConditionalComponent />}
</form></FormProvider>
);
}
Example 1: Simple Toggle
Let's say you have a form with a checkbox that toggles the visibility of additional fields:
jsx
importReactfrom"react";
import { useForm, useWatch, FormProvider } from"react-hook-form";
functionToggleFieldsForm() {
const methods = useForm({
defaultValues: {
enableAdditionalFields: false,
additionalField1: "",
additionalField2: ""
}
});
// This will trigger re-renders when the value changesconst showAdditionalFields = useWatch({
control: methods.control,
name: "enableAdditionalFields",
defaultValue: false
});
return (
<FormProvider {...methods}><formonSubmit={methods.handleSubmit(data => console.log(data))}>
<div><label><inputtype="checkbox"
{...methods.register("enableAdditionalFields")}
/>
Show additional fields
</label></div>
{showAdditionalFields && (
<divclassName="additional-fields"><div><label>Additional Field 1</label><input {...methods.register("additionalField1")} /></div><div><label>Additional Field 2</label><input {...methods.register("additionalField2")} /></div></div>
)}
<buttontype="submit">Submit</button></form></FormProvider>
);
}
Example 2: Complex Conditional Logic
For more complex scenarios, like an opening hours form where different sections appear based on multiple conditions:
In React 19, use useWatch instead of watch for values that need to trigger UI updates
Always provide a defaultValue to useWatch to ensure consistency during the initial render
For optimal performance, only use useWatch for values that directly affect rendering; continue using watch for other cases
By following these guidelines, your React Hook Form components will behave as expected in React 19, with reliable re-rendering when form values change.
Remember, this change is particularly important if you're:
Using conditional rendering based on form values
Showing/hiding form sections based on toggles
Implementing dynamic form logic that depends on the current state of form values