Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -867,6 +867,7 @@ describe('ReactLazy', () => {
return props.inner + props.outer;
};
Add = React.memo(Add);
Add.displayName = 'Add';
Add.propTypes = {
inner: PropTypes.number.isRequired,
innerWithDefault: PropTypes.number.isRequired,
Expand All @@ -882,6 +883,7 @@ describe('ReactLazy', () => {
return props.inner + props.outer;
};
Add = React.memo(Add);
Add.displayName = 'Add';
Add.propTypes = {
inner: PropTypes.number.isRequired,
};
Expand Down Expand Up @@ -945,7 +947,7 @@ describe('ReactLazy', () => {
expect(() => {
expect(Scheduler).toFlushAndYield(['Inner default text']);
}).toErrorDev(
'The prop `text` is marked as required in `T`, but its value is `undefined`',
'The prop `text` is marked as required in `Memo(T)`, but its value is `undefined`',
);
expect(root).toMatchRenderedOutput('Inner default text');

Expand All @@ -958,7 +960,7 @@ describe('ReactLazy', () => {
);
expect(Scheduler).toFlushAndYield([null]);
}).toErrorDev(
'The prop `text` is marked as required in `T`, but its value is `null`',
'The prop `text` is marked as required in `Memo(T)`, but its value is `null`',
);
expect(root).toMatchRenderedOutput(null);
});
Expand Down Expand Up @@ -1050,6 +1052,7 @@ describe('ReactLazy', () => {
Add.defaultProps = {
inner: 2,
};
Add.displayName = 'Add';
const LazyAdd = lazy(() => fakeImport(Add));
const root = ReactTestRenderer.create(
<Suspense fallback={<Text text="Loading..." />}>
Expand Down
14 changes: 7 additions & 7 deletions packages/react-reconciler/src/__tests__/ReactMemo-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -365,7 +365,7 @@ describe('memo', () => {
expect(Scheduler).toFlushWithoutYielding();
}).toErrorDev(
// Outer props are checked in createElement
'Invalid prop `outer` of type `string` supplied to `FnInner`, expected `number`.',
'Invalid prop `outer` of type `string` supplied to `Memo(FnInner)`, expected `number`.',
);

// Update
Expand All @@ -374,7 +374,7 @@ describe('memo', () => {
expect(Scheduler).toFlushWithoutYielding();
}).toErrorDev(
// Outer props are checked in createElement
'Invalid prop `outer` of type `boolean` supplied to `FnInner`, expected `number`.',
'Invalid prop `outer` of type `boolean` supplied to `Memo(FnInner)`, expected `number`.',
);
});

Expand Down Expand Up @@ -408,8 +408,8 @@ describe('memo', () => {
);
expect(Scheduler).toFlushWithoutYielding();
}).toErrorDev([
'Invalid prop `outer` of type `string` supplied to `Inner`, expected `number`.',
'Invalid prop `middle` of type `string` supplied to `Inner`, expected `number`.',
'Invalid prop `outer` of type `string` supplied to `Memo(Memo(Inner))`, expected `number`.',
'Invalid prop `middle` of type `string` supplied to `Memo(Inner)`, expected `number`.',
'Invalid prop `inner` of type `string` supplied to `Inner`, expected `number`.',
]);

Expand All @@ -422,8 +422,8 @@ describe('memo', () => {
);
expect(Scheduler).toFlushWithoutYielding();
}).toErrorDev([
'Invalid prop `outer` of type `boolean` supplied to `Inner`, expected `number`.',
'Invalid prop `middle` of type `boolean` supplied to `Inner`, expected `number`.',
'Invalid prop `outer` of type `boolean` supplied to `Memo(Memo(Inner))`, expected `number`.',
'Invalid prop `middle` of type `boolean` supplied to `Memo(Inner)`, expected `number`.',
'Invalid prop `inner` of type `boolean` supplied to `Inner`, expected `number`.',
]);
});
Expand Down Expand Up @@ -532,7 +532,7 @@ describe('memo', () => {
ReactNoop.render(<MemoComponent optional="foo" />),
).toErrorDev(
'Warning: Failed prop type: The prop `required` is marked as required in ' +
'`Foo`, but its value is `undefined`.\n' +
'`Bar`, but its value is `undefined`.\n' +
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test was added in #18925 but I don't think this should've been the expected behavior @bvaughn.

For React.memo we ignore displayName on the wrapper if we have a displayName on the wrapped component.
For React.forwardRef we honor displayName on the wrapper even if we have displayName on the wrapped component.

I think it is confusing that React.memo and React.forwardRef behave differently with regard to displayName.

' in Foo (at **)',
);
});
Expand Down
6 changes: 3 additions & 3 deletions packages/shared/getComponentName.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@ function getWrappedName(
innerType: any,
wrapperName: string,
): string {
const functionName = innerType.displayName || innerType.name || '';
const innerName = getComponentName(innerType) || '';
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This may be a bit overkill for render functions of forwardRef. We could extract the logic of innerName to the call-site of getComponentName.

return (
(outerType: any).displayName ||
(functionName !== '' ? `${wrapperName}(${functionName})` : wrapperName)
(innerName !== '' ? `${wrapperName}(${innerName})` : wrapperName)
);
}

Expand Down Expand Up @@ -85,7 +85,7 @@ function getComponentName(type: mixed): string | null {
case REACT_FORWARD_REF_TYPE:
return getWrappedName(type, type.render, 'ForwardRef');
case REACT_MEMO_TYPE:
return getComponentName(type.type);
return getWrappedName(type, type.type, 'Memo');
case REACT_BLOCK_TYPE:
return getComponentName(type._render);
case REACT_LAZY_TYPE: {
Expand Down