Fix: use Object.is for dependency comparison to handle NaN correctly#36034
Closed
MorikawaSouma wants to merge 2 commits intofacebook:mainfrom
Closed
Fix: use Object.is for dependency comparison to handle NaN correctly#36034MorikawaSouma wants to merge 2 commits intofacebook:mainfrom
MorikawaSouma wants to merge 2 commits intofacebook:mainfrom
Conversation
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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