facebook / react

The library for web and native user interfaces.
https://react.dev
MIT License
229.56k stars 47k forks source link

[Compiler Bug]: `===` is not a sufficient equality check #31359

Open Skalman opened 4 weeks ago

Skalman commented 4 weeks ago

What kind of issue is this?

Link to repro

https://playground.react.dev/#N4Igzg9grgTgxgUxALhASwLYAcIwC4AEwBUYCAyngIZ4IEC+BAZjBBgQDogwJVx5cA3BwB2ohAA8c+AgBMETKlAA2hJlBH80EEQQBaCVgAoAlEVEECcHWEIBtAF6GIAGgJk8B1gF0CAXhIyShoEIwAGE2FdKxtCWxh-AgB5ACMAKwR+ADo0MCMnVjcIggB+ThAwrgJkcoBaSpAoyx48WF0AHhSoPDwdAh0AYWU0OABrP2BTfwA+dwRPZyNagogTemngePp2gHounp1pqPpREHogA

Repro steps

  1. Click the rendered button repeatedly

Expected result:

On each click, the text should toggle between 0 and -0.

Actual result:

Initially, the text 0 is rendered. After the first click, -0 is rendered. Subsequent clicks don't do anything.

How often does this bug happen?

Every time

What version of React are you using?

18.3.1

What version of React Compiler are you using?

19.0.0-beta-8a03594-20241020


React Compiler currently uses the === operator to check whether to memoize. The === operator isn't sufficient to check whether two values are identical. The two edge cases missed by === but handled handled by Object.is():

I imagine that changing === to Object.is() in the output might be bad for performance. In case this bug is a wontfix, you should document this limitation somewhere.

josephsavona commented 3 weeks ago

Thanks for posting! We considered this early in the design of the compiler and chose to use === for performance reasons. We've also found that in practice this isn't an issue — apps generally don't run into circumstances where they have -0 or NaN in the UI.

That said, we will definitely update the docs to reflect this choice. We'll also consider adding an option to use Object.is() since there can be circumstances where the difference is observable. If we do, we can use our type inference to prefer === when the value is known not to be a number.