@samitouri / QOS-React / commits / efa71484b3

Warn about unresolved function as a child (#10376)

* Warn about unresolved function as a child * Oops

Dan Abramov committed Aug 4, 2017 at 15:51 UTC efa71484b334153958d8a0f35310c3c4ee72c731
2 files changed +112 -2
src/renderers/__tests__/ReactComponent-test.js
+76 -2
@@ -14,9 +14,10 @@
14 var React;
15 var ReactDOM;
16 var ReactDOMServer;
17 -var ReactDOMFeatureFlags;
17 var ReactTestUtils;
18
19 +var ReactDOMFeatureFlags = require('ReactDOMFeatureFlags');
20 +
21 describe('ReactComponent', () => {
22 function normalizeCodeLocInfo(str) {
23 return str && str.replace(/\(at .+?:\d+\)/g, '(at **)');
@@ -26,7 +27,6 @@ describe('ReactComponent', () => {
27 React = require('react');
28 ReactDOM = require('react-dom');
29 ReactDOMServer = require('react-dom/server');
29 - ReactDOMFeatureFlags = require('ReactDOMFeatureFlags');
30 ReactTestUtils = require('react-dom/test-utils');
31 });
32
@@ -493,4 +493,78 @@ describe('ReactComponent', () => {
493 ' in Foo (at **)',
494 );
495 });
496 +
497 + if (ReactDOMFeatureFlags.useFiber) {
498 + describe('with new features', () => {
499 + beforeEach(() => {
500 + require('ReactFeatureFlags').disableNewFiberFeatures = false;
501 + });
502 +
503 + it('warns on function as a return value from a function', () => {
504 + function Foo() {
505 + return Foo;
506 + }
507 + spyOn(console, 'error');
508 + var container = document.createElement('div');
509 + ReactDOM.render(<Foo />, container);
510 + expectDev(console.error.calls.count()).toBe(1);
511 + expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe(
512 + 'Warning: Functions are not valid as a React child. This may happen if ' +
513 + 'you return a Component instead of <Component /> from render. ' +
514 + 'Or maybe you meant to call this function rather than return it.\n' +
515 + ' in Foo (at **)',
516 + );
517 + });
518 +
519 + it('warns on function as a return value from a class', () => {
520 + class Foo extends React.Component {
521 + render() {
522 + return Foo;
523 + }
524 + }
525 + spyOn(console, 'error');
526 + var container = document.createElement('div');
527 + ReactDOM.render(<Foo />, container);
528 + expectDev(console.error.calls.count()).toBe(1);
529 + expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe(
530 + 'Warning: Functions are not valid as a React child. This may happen if ' +
531 + 'you return a Component instead of <Component /> from render. ' +
532 + 'Or maybe you meant to call this function rather than return it.\n' +
533 + ' in Foo (at **)',
534 + );
535 + });
536 +
537 + it('warns on function as a child to host component', () => {
538 + function Foo() {
539 + return <div><span>{Foo}</span></div>;
540 + }
541 + spyOn(console, 'error');
542 + var container = document.createElement('div');
543 + ReactDOM.render(<Foo />, container);
544 + expectDev(console.error.calls.count()).toBe(1);
545 + expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe(
546 + 'Warning: Functions are not valid as a React child. This may happen if ' +
547 + 'you return a Component instead of <Component /> from render. ' +
548 + 'Or maybe you meant to call this function rather than return it.\n' +
549 + ' in span (at **)\n' +
550 + ' in div (at **)\n' +
551 + ' in Foo (at **)',
552 + );
553 + });
554 +
555 + it('does not warn for function-as-a-child that gets resolved', () => {
556 + function Bar(props) {
557 + return props.children();
558 + }
559 + function Foo() {
560 + return <Bar>{() => 'Hello'}</Bar>;
561 + }
562 + spyOn(console, 'error');
563 + var container = document.createElement('div');
564 + ReactDOM.render(<Foo />, container);
565 + expect(container.innerHTML).toBe('Hello');
566 + expectDev(console.error.calls.count()).toBe(0);
567 + });
568 + });
569 + }
570 });
src/renderers/shared/fiber/ReactChildFiber.js
+36
@@ -200,6 +200,16 @@ function throwOnInvalidObjectType(returnFiber: Fiber, newChild: Object) {
200 }
201 }
202
203 +function warnOnFunctionType() {
204 + warning(
205 + false,
206 + 'Functions are not valid as a React child. This may happen if ' +
207 + 'you return a Component instead of <Component /> from render. ' +
208 + 'Or maybe you meant to call this function rather than return it.%s',
209 + getCurrentFiberStackAddendum() || '',
210 + );
211 +}
212 +
213 // This wrapper function exists because I expect to clone the code in each path
214 // to be able to optimize each path individually by branching early. This needs
215 // a compiler or we can do it manually. Helpers that don't need this branching
@@ -565,6 +575,13 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
575 throwOnInvalidObjectType(returnFiber, newChild);
576 }
577
578 + if (__DEV__) {
579 + const disableNewFiberFeatures = ReactFeatureFlags.disableNewFiberFeatures;
580 + if (!disableNewFiberFeatures && typeof newChild === 'function') {
581 + warnOnFunctionType();
582 + }
583 + }
584 +
585 return null;
586 }
587
@@ -638,6 +655,13 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
655 throwOnInvalidObjectType(returnFiber, newChild);
656 }
657
658 + if (__DEV__) {
659 + const disableNewFiberFeatures = ReactFeatureFlags.disableNewFiberFeatures;
660 + if (!disableNewFiberFeatures && typeof newChild === 'function') {
661 + warnOnFunctionType();
662 + }
663 + }
664 +
665 return null;
666 }
667
@@ -697,6 +721,13 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
721 throwOnInvalidObjectType(returnFiber, newChild);
722 }
723
724 + if (__DEV__) {
725 + const disableNewFiberFeatures = ReactFeatureFlags.disableNewFiberFeatures;
726 + if (!disableNewFiberFeatures && typeof newChild === 'function') {
727 + warnOnFunctionType();
728 + }
729 + }
730 +
731 return null;
732 }
733
@@ -1418,6 +1449,11 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
1449 throwOnInvalidObjectType(returnFiber, newChild);
1450 }
1451
1452 + if (__DEV__) {
1453 + if (!disableNewFiberFeatures && typeof newChild === 'function') {
1454 + warnOnFunctionType();
1455 + }
1456 + }
1457 if (!disableNewFiberFeatures && typeof newChild === 'undefined') {
1458 // If the new child is undefined, and the return fiber is a composite
1459 // component, throw an error. If Fiber return types are disabled,