@samitouri / QOS-React-2 / commits / e49f3ca08e

honor displayName set on ForwardRef if available (#13615)

honor displayName set on ForwardRef if available (#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

Evan Jacobs committed Sep 11, 2018 at 14:19 UTC e49f3ca08e0dc8ac050f92b45a7734fa60d86e22
3 files changed +36 -4
packages/react/src/ReactElementValidator.js
+3 -1
@@ -197,7 +197,9 @@ function validatePropTypes(element) {
197 ) {
198 // ForwardRef
199 const functionName = type.render.displayName || type.render.name || '';
200 - name = functionName !== '' ? `ForwardRef(${functionName})` : 'ForwardRef';
200 + name =
201 + type.displayName ||
202 + (functionName !== '' ? `ForwardRef(${functionName})` : 'ForwardRef');
203 propTypes = type.propTypes;
204 } else {
205 return;
packages/react/src/__tests__/forwardRef-test.js
+29
@@ -181,4 +181,33 @@ describe('forwardRef', () => {
181 {withoutStack: true},
182 );
183 });
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 + });
213 });
packages/shared/getComponentName.js
+4 -3
@@ -66,9 +66,10 @@ function getComponentName(type: mixed): string | null {
66 case REACT_FORWARD_REF_TYPE:
67 const renderFn = (type.render: any);
68 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 + );
73 }
74 if (typeof type.then === 'function') {
75 const thenable: Thenable<mixed> = (type: any);