Skip to content

Commit df4d74d

Browse files
quantizorSimek
authored andcommitted
honor displayName set on ForwardRef if available (facebook#13615)
* add failing test * honor displayName set on ForwardRef if available Since React.forwardRef returns a component object, some users (including styled-components and react-native) are starting to decorate them with various statics including displayName. This adjusts React's various name-getters to honor this if set and surface the name in warnings and hopefully DevTools. * fix typing * Refine later
1 parent 614588d commit df4d74d

File tree

3 files changed

+36
-4
lines changed

3 files changed

+36
-4
lines changed

packages/react/src/ReactElementValidator.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,9 @@ function validatePropTypes(element) {
197197
) {
198198
// ForwardRef
199199
const functionName = type.render.displayName || type.render.name || '';
200-
name = functionName !== '' ? `ForwardRef(${functionName})` : 'ForwardRef';
200+
name =
201+
type.displayName ||
202+
(functionName !== '' ? `ForwardRef(${functionName})` : 'ForwardRef');
201203
propTypes = type.propTypes;
202204
} else {
203205
return;

packages/react/src/__tests__/forwardRef-test.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,4 +181,33 @@ describe('forwardRef', () => {
181181
{withoutStack: true},
182182
);
183183
});
184+
185+
it('should honor a displayName if set on the forwardRef wrapper in warnings', () => {
186+
const Component = props => <div {...props} />;
187+
188+
const RefForwardingComponent = React.forwardRef((props, ref) => (
189+
<Component {...props} forwardedRef={ref} />
190+
));
191+
192+
RefForwardingComponent.displayName = 'Foo';
193+
194+
RefForwardingComponent.propTypes = {
195+
optional: PropTypes.string,
196+
required: PropTypes.string.isRequired,
197+
};
198+
199+
RefForwardingComponent.defaultProps = {
200+
optional: 'default',
201+
};
202+
203+
const ref = React.createRef();
204+
205+
expect(() =>
206+
ReactNoop.render(<RefForwardingComponent ref={ref} optional="foo" />),
207+
).toWarnDev(
208+
'Warning: Failed prop type: The prop `required` is marked as required in ' +
209+
'`Foo`, but its value is `undefined`.\n' +
210+
' in Foo (at **)',
211+
);
212+
});
184213
});

packages/shared/getComponentName.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,10 @@ function getComponentName(type: mixed): string | null {
6666
case REACT_FORWARD_REF_TYPE:
6767
const renderFn = (type.render: any);
6868
const functionName = renderFn.displayName || renderFn.name || '';
69-
return functionName !== ''
70-
? `ForwardRef(${functionName})`
71-
: 'ForwardRef';
69+
return (
70+
(type: any).displayName ||
71+
(functionName !== '' ? `ForwardRef(${functionName})` : 'ForwardRef')
72+
);
7273
}
7374
if (typeof type.then === 'function') {
7475
const thenable: Thenable<mixed> = (type: any);

0 commit comments

Comments
 (0)