Skip to content

Commit 9e3c4ba

Browse files
committed
Fast-path SimpleMemoComponent with custom compare
1 parent 6eda534 commit 9e3c4ba

3 files changed

Lines changed: 21 additions & 6 deletions

File tree

packages/react-devtools-shared/src/__tests__/profilerChangeDescriptions-test.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,7 @@ describe('Profiler change descriptions', () => {
7676
▾ <App>
7777
▾ <Context.Provider>
7878
<Child>
79-
▾ <Child> [Memo]
80-
<Child>
79+
<Child> [Memo]
8180
▾ <RefForwardingComponent> [ForwardRef]
8281
<Child>
8382
`);

packages/react-devtools-shared/src/__tests__/store-test.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1893,6 +1893,11 @@ describe('Store', () => {
18931893
ForwardRefComponentWithCustomDisplayName.displayName = 'Custom';
18941894
const MyComponent4 = (props, ref) => null;
18951895
const MemoComponent = React.memo(MyComponent4);
1896+
const MyComponent5 = (props, ref) => null;
1897+
const MemoComponentWithCustomCompare = React.memo(
1898+
MyComponent5,
1899+
(a, b) => a === b,
1900+
);
18961901
const MemoForwardRefComponent = React.memo(ForwardRefComponent);
18971902

18981903
const FakeHigherOrderComponent = () => null;
@@ -1922,6 +1927,7 @@ describe('Store', () => {
19221927
<ForwardRefComponentWithAnonymousFunction />
19231928
<ForwardRefComponentWithCustomDisplayName />
19241929
<MemoComponent />
1930+
<MemoComponentWithCustomCompare />
19251931
<MemoForwardRefComponent />
19261932
<FakeHigherOrderComponent />
19271933
<MemoizedFakeHigherOrderComponent />
@@ -1948,6 +1954,7 @@ describe('Store', () => {
19481954
<MyComponent2>
19491955
<Custom>
19501956
<MyComponent4> [Memo]
1957+
<MyComponent5> [Memo]
19511958
▾ <MyComponent> [Memo]
19521959
<MyComponent> [ForwardRef]
19531960
<Baz> [withFoo][withBar]

packages/react-reconciler/src/ReactFiberBeginWork.js

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,12 @@ export const SelectiveHydrationException: mixed = new Error(
318318

319319
let didReceiveUpdate: boolean = false;
320320

321+
// Map from SimpleMemoComponent function to compare a.k.a. arePropsEqual function.
322+
const simpleMemoComponentToCompare = new WeakMap<
323+
Function,
324+
(objA: mixed, objB: mixed) => boolean,
325+
>();
326+
321327
let didWarnAboutBadClass;
322328
let didWarnAboutContextTypeOnFunctionComponent;
323329
let didWarnAboutContextTypes;
@@ -478,16 +484,18 @@ function updateMemoComponent(
478484
): null | Fiber {
479485
if (current === null) {
480486
const type = Component.type;
481-
if (isSimpleFunctionComponent(type) && Component.compare === null) {
487+
if (isSimpleFunctionComponent(type)) {
482488
let resolvedType = type;
483489
if (__DEV__) {
484490
resolvedType = resolveFunctionForHotReloading(type);
485491
}
486492
// If this is a plain function component without default props,
487-
// and with only the default shallow comparison, we upgrade it
488-
// to a SimpleMemoComponent to allow fast path updates.
493+
// we upgrade it to a SimpleMemoComponent to allow fast path updates.
489494
workInProgress.tag = SimpleMemoComponent;
490495
workInProgress.type = resolvedType;
496+
if (Component.compare) {
497+
simpleMemoComponentToCompare.set(resolvedType, Component.compare);
498+
}
491499
if (__DEV__) {
492500
validateFunctionComponentInDev(workInProgress, type);
493501
}
@@ -548,9 +556,10 @@ function updateSimpleMemoComponent(
548556
// hasn't yet mounted. This happens when the inner render suspends.
549557
// We'll need to figure out if this is fine or can cause issues.
550558
if (current !== null) {
559+
const compare = simpleMemoComponentToCompare.get(Component) ?? shallowEqual;
551560
const prevProps = current.memoizedProps;
552561
if (
553-
shallowEqual(prevProps, nextProps) &&
562+
compare(prevProps, nextProps) &&
554563
current.ref === workInProgress.ref &&
555564
// Prevent bailout if the implementation changed due to hot reload.
556565
(__DEV__ ? workInProgress.type === current.type : true)

0 commit comments

Comments
 (0)