Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Compiler Bug]: value read during render does not update when using react-hook-form .watch API #29144

Closed
1 of 4 tasks
erikshestopal opened this issue May 17, 2024 · 4 comments
Closed
1 of 4 tasks
Labels
Component: Optimizing Compiler Status: Unconfirmed A potential issue that we haven't yet confirmed as a bug Type: Bug

Comments

@erikshestopal
Copy link

What kind of issue is this?

  • React Compiler core (the JS output is incorrect, or your app works incorrectly after optimization)
  • babel-plugin-react-compiler (build issue installing or using the Babel plugin)
  • eslint-plugin-react-compiler (build issue installing or using the eslint plugin)
  • react-compiler-healthcheck (build issue installing or using the healthcheck script)

Link to repro

https://github.com/erikshestopal/react-compiler-bug

Repro steps

Reproduction steps:

  1. Clone the repo
  2. Run bun install
  3. Run bun dev to start the dev server
  4. Type in a value into the customer ID text field
  5. Expect the address ID text field to show up but it does not

When trying to read a value during render using react-hook-form's .watch API with the babel-plugin-react-compiler plugin enabled, the value is not updated and the component that is supposed to be rendered conditionally never renders.

How often does this bug happen?

Every time

What version of React are you using?

19.0.0-rc-3f1436cca1-20240516

@erikshestopal erikshestopal added Component: Optimizing Compiler Status: Unconfirmed A potential issue that we haven't yet confirmed as a bug Type: Bug labels May 17, 2024
@erikshestopal erikshestopal changed the title [Compiler Bug]: [Compiler Bug]: value read during render does not update when using react-hook-form .watch API May 17, 2024
@josephsavona
Copy link
Contributor

josephsavona commented May 17, 2024

Thanks for filing this. If i'm understanding correctly, the issue is with the following two lines:

const form = useForm({ defaultValues: { customerId: "", addressId: "" } });
const customerId = form.watch("customerId");

Where the customerId isn't updating when React Compiler is applied.

React Compiler is applying the equivalent of the following to this code:

const form = useForm({ defaultValues: { customerId: "", addressId: "" } });
const customerId = useMemo(() => form.watch("customerId"), [form]);

If you do the same, and apply useMemo (without the compiler), does customerId update as you'd expect? Note that React components must be pure/idempotent. If props, state, and context haven't changed, then the component is expected to return the same result. Since form is the same, it's expected that customerId would be the same too. So it would help to understand if customerId updates if you use the useMemo version without compiler applied.

@erikshestopal
Copy link
Author

@josephsavona Thanks for the quick response.

If you do the same, and apply useMemo (without the compiler), does customerId update as you'd expect?

const form = useForm({ defaultValues: { customerId: "", addressId: "" } });
const customerId = useMemo(() => form.watch("customerId"), [form]);

If I apply this change manually without the compiler enabled, I still get the same result (customerId not being updated) because as you mentioned, form remains the same across re-renders.

I can get around issue using the useWatch hook react-hook-form provides but it was unexpected that the behavior changed with the compiler enabled.

@josephsavona
Copy link
Contributor

Thanks for confirming. As I noted above, React expects components to be idempotent and only update if their props, state, or context changes. It looks like the watch() API isn't using state to tell React that something has changed, which goes against React's rules around idempotency.

The useWatch() API looks like it does use internal state to tell React when changes occur, so that should work just fine (both with useMemo and React Compiler).

@erikshestopal
Copy link
Author

Got it - thanks! Will close out then since this works as expected when using useWatch.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Component: Optimizing Compiler Status: Unconfirmed A potential issue that we haven't yet confirmed as a bug Type: Bug
Projects
None yet
Development

No branches or pull requests

2 participants