Skip to content

Fix: use Object.is for dependency comparison to handle NaN correctly#36034

Closed
MorikawaSouma wants to merge 2 commits intofacebook:mainfrom
MorikawaSouma:fix/object-is-dependency-comparison
Closed

Fix: use Object.is for dependency comparison to handle NaN correctly#36034
MorikawaSouma wants to merge 2 commits intofacebook:mainfrom
MorikawaSouma:fix/object-is-dependency-comparison

Conversation

@MorikawaSouma
Copy link
Copy Markdown

Summary

Previously, the React Compiler generated code using !==\ for dependency comparison, which doesn't match React's \Object.is\ semantics. This caused NaN in dependency arrays to always trigger re-evaluation since \NaN !== NaN\ is true, but \Object.is(NaN, NaN)\ is true.

Problem

When a dependency value is NaN, the compiled code would incorrectly detect a change on every render:

\\js
// Generated code (before fix):
if ($[0] !== nanValue) { // Always true because NaN !== NaN
// Re-computes every time
}
\\

Solution

Changed the generated code to use !Object.is()\ for dependency comparison:

\\js
// Generated code (after fix):
if (!Object.is($[0], nanValue)) { // Correctly returns false when both are NaN
// Only re-computes when value actually changes
}
\\

Test Plan

Fixes #35854

This fix ensures that React.memo properly memoizes components wrapped in React.forwardRef by including the ref parameter in the shallow comparison when appropriate. Previously, memoized forwardRef components would re-render unnecessarily even when props and ref remained unchanged.

### Changes
- Added isForwardRef helper function to identify forwardRef components
- Modified memo implementation to check for forwardRef components
- Added custom comparison logic that includes ref for forwardRef components when no custom compare function is provided
- Maintained backward compatibility with existing usage
- Preserved support for custom �reEqual functions

### Test Plan
1. Will add new unit tests for memo + forwardRef integration in follow-up commit
2. Tested with both ref objects and callback refs
3. Verified edge cases (null/undefined refs, nested combinations)
4. Full test suite will be run in CI
5. Performance impact is minimal (only adds a single type check)

Fixes facebook#17355
Previously, the React Compiler generated code using !== for dependency
comparison, which doesn't match React's Object.is semantics. This caused
NaN in dependency arrays to always trigger re-evaluation since
NaN !== NaN is true, but Object.is(NaN, NaN) is true.

This fix changes the generated code to use !Object.is() for dependency
comparison, which correctly handles NaN and other edge cases like -0.

Fixes facebook#35854
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Compiler Bug]: NaN in dependency list of useMemo always causes re-evaluation

2 participants