@samitouri / QOS-React / commits / a63893ff32

Warn about undefined return value for memo and forwardRef (#19550)

Brian Vaughn committed Aug 6, 2020 at 16:12 UTC a63893ff320c39802e8c37fca84ea023f55230c9
3 files changed +34 -6
packages/react-dom/src/__tests__/ReactEmptyComponent-test.js
+20
@@ -316,4 +316,24 @@ describe('ReactEmptyComponent', () => {
316 const noscript2 = container.firstChild;
317 expect(noscript2).toBe(null);
318 });
319 +
320 + it('should warn about React.forwardRef that returns undefined', () => {
321 + const Empty = () => {};
322 + const EmptyForwardRef = React.forwardRef(Empty);
323 +
324 + expect(() => {
325 + ReactTestUtils.renderIntoDocument(<EmptyForwardRef />);
326 + }).toThrowError(
327 + 'ForwardRef(Empty)(...): Nothing was returned from render.',
328 + );
329 + });
330 +
331 + it('should warn about React.memo that returns undefined', () => {
332 + const Empty = () => {};
333 + const EmptyMemo = React.memo(Empty);
334 +
335 + expect(() => {
336 + ReactTestUtils.renderIntoDocument(<EmptyMemo />);
337 + }).toThrowError('Empty(...): Nothing was returned from render.');
338 + });
339 });
packages/react-reconciler/src/ReactChildFiber.new.js
+7 -3
@@ -29,7 +29,9 @@ import {
29 ClassComponent,
30 HostText,
31 HostPortal,
32 + ForwardRef,
33 Fragment,
34 + SimpleMemoComponent,
35 Block,
36 } from './ReactWorkTags';
37 import invariant from 'shared/invariant';
@@ -1393,14 +1395,16 @@ function ChildReconciler(shouldTrackSideEffects) {
1395 // Intentionally fall through to the next case, which handles both
1396 // functions and classes
1397 // eslint-disable-next-lined no-fallthrough
1396 - case FunctionComponent: {
1397 - const Component = returnFiber.type;
1398 + case Block:
1399 + case FunctionComponent:
1400 + case ForwardRef:
1401 + case SimpleMemoComponent: {
1402 invariant(
1403 false,
1404 '%s(...): Nothing was returned from render. This usually means a ' +
1405 'return statement is missing. Or, to render nothing, ' +
1406 'return null.',
1403 - Component.displayName || Component.name || 'Component',
1407 + getComponentName(returnFiber.type) || 'Component',
1408 );
1409 }
1410 }
packages/react-reconciler/src/ReactChildFiber.old.js
+7 -3
@@ -29,7 +29,9 @@ import {
29 ClassComponent,
30 HostText,
31 HostPortal,
32 + ForwardRef,
33 Fragment,
34 + SimpleMemoComponent,
35 Block,
36 } from './ReactWorkTags';
37 import invariant from 'shared/invariant';
@@ -1385,14 +1387,16 @@ function ChildReconciler(shouldTrackSideEffects) {
1387 // Intentionally fall through to the next case, which handles both
1388 // functions and classes
1389 // eslint-disable-next-lined no-fallthrough
1388 - case FunctionComponent: {
1389 - const Component = returnFiber.type;
1390 + case Block:
1391 + case FunctionComponent:
1392 + case ForwardRef:
1393 + case SimpleMemoComponent: {
1394 invariant(
1395 false,
1396 '%s(...): Nothing was returned from render. This usually means a ' +
1397 'return statement is missing. Or, to render nothing, ' +
1398 'return null.',
1395 - Component.displayName || Component.name || 'Component',
1399 + getComponentName(returnFiber.type) || 'Component',
1400 );
1401 }
1402 }