From bfea8eeccf66805df92fcb350d5f3a009de1761b Mon Sep 17 00:00:00 2001 From: Andrey Saleba Date: Thu, 5 Oct 2017 20:48:27 +0300 Subject: [PATCH 1/4] Added check to deduplicate function type warning calls on each component type --- src/renderers/shared/fiber/ReactChildFiber.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/renderers/shared/fiber/ReactChildFiber.js b/src/renderers/shared/fiber/ReactChildFiber.js index 8eae6f410090d..763ee6d9f3c97 100644 --- a/src/renderers/shared/fiber/ReactChildFiber.js +++ b/src/renderers/shared/fiber/ReactChildFiber.js @@ -35,6 +35,7 @@ if (__DEV__) { * updates. */ var ownerHasKeyUseWarning = {}; + var ownerHasFunctionTypeWarning = {}; var warnForMissingKey = (child: mixed) => { if (child === null || typeof child !== 'object') { @@ -192,6 +193,17 @@ function throwOnInvalidObjectType(returnFiber: Fiber, newChild: Object) { } function warnOnFunctionType() { + const currentComponentErrorInfo = + 'Functions are not valid as a React child. This may happen if ' + + 'you return a Component instead of from render. ' + + 'Or maybe you meant to call this function rather than return it.' + + (getCurrentFiberStackAddendum() || ''); + + if (ownerHasFunctionTypeWarning[currentComponentErrorInfo]) { + return; + } + ownerHasFunctionTypeWarning[currentComponentErrorInfo] = true; + warning( false, 'Functions are not valid as a React child. This may happen if ' + From 17847a0cb8f3fa72fba6a02d222b988004440e77 Mon Sep 17 00:00:00 2001 From: Andrey Saleba Date: Fri, 6 Oct 2017 09:55:35 +0300 Subject: [PATCH 2/4] Added test to check that 'function type as React child' warning is deduplicated correctly by component type --- .../__tests__/ReactComponent-test.js | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/renderers/__tests__/ReactComponent-test.js b/src/renderers/__tests__/ReactComponent-test.js index 86a22155f36d3..94fd92dceab0b 100644 --- a/src/renderers/__tests__/ReactComponent-test.js +++ b/src/renderers/__tests__/ReactComponent-test.js @@ -542,5 +542,36 @@ describe('ReactComponent', () => { expect(container.innerHTML).toBe('Hello'); expectDev(console.error.calls.count()).toBe(0); }); + + it('deduplicates function type warnings based on component type', () => { + spyOn(console, 'error'); + function Foo() { + return ( +
+ {Foo}{Foo} + {Foo}{Foo} +
+ ); + } + var container = document.createElement('div'); + ReactDOM.render(, container); + + expectDev(console.error.calls.count()).toBe(2); + expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe( + 'Warning: Functions are not valid as a React child. This may happen if ' + + 'you return a Component instead of from render. ' + + 'Or maybe you meant to call this function rather than return it.\n' + + ' in div (at **)\n' + + ' in Foo (at **)', + ); + expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(1)[0])).toBe( + 'Warning: Functions are not valid as a React child. This may happen if ' + + 'you return a Component instead of from render. ' + + 'Or maybe you meant to call this function rather than return it.\n' + + ' in span (at **)\n' + + ' in div (at **)\n' + + ' in Foo (at **)', + ); + }); }); }); From 00ca5eed63acdafbaaf7940cd7817838ff1557e2 Mon Sep 17 00:00:00 2001 From: Andrey Saleba Date: Fri, 6 Oct 2017 10:07:22 +0300 Subject: [PATCH 3/4] Ran prettier on added code --- src/renderers/__tests__/ReactComponent-test.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/renderers/__tests__/ReactComponent-test.js b/src/renderers/__tests__/ReactComponent-test.js index 94fd92dceab0b..357fa12bedd63 100644 --- a/src/renderers/__tests__/ReactComponent-test.js +++ b/src/renderers/__tests__/ReactComponent-test.js @@ -559,18 +559,18 @@ describe('ReactComponent', () => { expectDev(console.error.calls.count()).toBe(2); expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe( 'Warning: Functions are not valid as a React child. This may happen if ' + - 'you return a Component instead of from render. ' + - 'Or maybe you meant to call this function rather than return it.\n' + - ' in div (at **)\n' + - ' in Foo (at **)', + 'you return a Component instead of from render. ' + + 'Or maybe you meant to call this function rather than return it.\n' + + ' in div (at **)\n' + + ' in Foo (at **)', ); expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(1)[0])).toBe( 'Warning: Functions are not valid as a React child. This may happen if ' + - 'you return a Component instead of from render. ' + - 'Or maybe you meant to call this function rather than return it.\n' + - ' in span (at **)\n' + - ' in div (at **)\n' + - ' in Foo (at **)', + 'you return a Component instead of from render. ' + + 'Or maybe you meant to call this function rather than return it.\n' + + ' in span (at **)\n' + + ' in div (at **)\n' + + ' in Foo (at **)', ); }); }); From 5852b597a503d81347a2ca28cce6aa8e6d5100eb Mon Sep 17 00:00:00 2001 From: Andrey Saleba Date: Fri, 6 Oct 2017 16:55:51 +0300 Subject: [PATCH 4/4] Modified test checking deduplication of 'Functions are not valid as a React child' warning so it will check against rerendering component now --- .../__tests__/ReactComponent-test.js | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/src/renderers/__tests__/ReactComponent-test.js b/src/renderers/__tests__/ReactComponent-test.js index 357fa12bedd63..8bca6d95d9d2f 100644 --- a/src/renderers/__tests__/ReactComponent-test.js +++ b/src/renderers/__tests__/ReactComponent-test.js @@ -545,17 +545,23 @@ describe('ReactComponent', () => { it('deduplicates function type warnings based on component type', () => { spyOn(console, 'error'); - function Foo() { - return ( -
- {Foo}{Foo} - {Foo}{Foo} -
- ); + class Foo extends React.PureComponent { + constructor() { + super(); + this.state = {type: 'mushrooms'}; + } + render() { + return ( +
+ {Foo}{Foo} + {Foo}{Foo} +
+ ); + } } var container = document.createElement('div'); - ReactDOM.render(, container); - + var component = ReactDOM.render(, container); + component.setState({type: 'portobello mushrooms'}); expectDev(console.error.calls.count()).toBe(2); expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe( 'Warning: Functions are not valid as a React child. This may happen if ' +