Add fast path for React.memo with custom compare #34540
Open
+21
−6
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
Fixes #33793
This widens the SimpleMemoComponent fast path introduced in #13903 to support memoized function components with custom props comparisons. The fast path eliminates the need for the wrapper MemoComponent to be tracked as a separate Fiber, reducing performance overhead.
In addition, React DevTools will show only one node for the component instead of two (because there is only one Fiber instead of two), which makes debugging easier by reducing visual and therefore mental clutter.
I considered several approaches as discussed in the issue before settling on this one as the best combination of simplicity, safety, and performance after benchmarking and prototyping.
How did you test this change?
Per the contributing instructions:
yarn test- two tests fail ("ReactFlightAsyncDebugInfo › can track async information when awaited" and "ReactFlightDOMEdge › should execute repeated host components only once") but these also fail atmain.yarn test --prod- 59 test failures but again this is the same asmain. Here they are if you want to see: https://gist.github.com/barryam3/82007cf5ef6b1c27621e0395ba9a1e71yarn prettieryarn lintyarn flow dom-node(I first triedyarn flowas recommended by the PR template, but it told me to pick a renderer, anddom-nodeis a good default)Additionally I updated the DevTools unit tests to reflect the component tree in DevTools.
yarn run build-for-devtoolsyarn run test-build-devtools- two tests fail ("ignoreList source map extension › for dev builds › should not ignore list anything" and "ignoreList source map extension › for production builds › should include every source") but these also fail atmainI made the equivalent change in my own application (thousands of components, hundreds memoized with custom arePropsEqual) via a pnpm patch and have not discovered any issues after running in production for about 2 months. I verified that this solves the "extra node" problem in DevTools. (In the interest of sharing any possible caveats, my app is still on React 18.2.0 and I chose a slightly simpler implementation for the patch of just setting a
comparefield on the function instead of using a Weak Map.)