diff --git a/packages/react-dom/src/__tests__/ReactUpdates-test.js b/packages/react-dom/src/__tests__/ReactUpdates-test.js index 1b86a59db3310..d37f4dbb66054 100644 --- a/packages/react-dom/src/__tests__/ReactUpdates-test.js +++ b/packages/react-dom/src/__tests__/ReactUpdates-test.js @@ -876,13 +876,9 @@ describe('ReactUpdates', () => { 'Invalid argument passed as callback. Expected a function. Instead ' + 'received: [object Object]', ); + // Make sure the warning is deduplicated and doesn't fire again component = ReactTestUtils.renderIntoDocument(); - expect(() => { - expect(() => component.setState({}, new Foo())).toWarnDev( - 'setState(...): Expected the last optional `callback` argument to be ' + - 'a function. Instead received: [object Object].', - ); - }).toThrowError( + expect(() => component.setState({}, new Foo())).toThrowError( 'Invalid argument passed as callback. Expected a function. Instead ' + 'received: [object Object]', ); @@ -923,13 +919,9 @@ describe('ReactUpdates', () => { 'Invalid argument passed as callback. Expected a function. Instead ' + 'received: [object Object]', ); + // Make sure the warning is deduplicated and doesn't fire again component = ReactTestUtils.renderIntoDocument(); - expect(() => { - expect(() => component.forceUpdate(new Foo())).toWarnDev( - 'forceUpdate(...): Expected the last optional `callback` argument to be ' + - 'a function. Instead received: [object Object].', - ); - }).toThrowError( + expect(() => component.forceUpdate(new Foo())).toThrowError( 'Invalid argument passed as callback. Expected a function. Instead ' + 'received: [object Object]', ); diff --git a/packages/react-reconciler/src/ReactFiberClassComponent.js b/packages/react-reconciler/src/ReactFiberClassComponent.js index 75ddf38169941..b5fcbd60f5bbe 100644 --- a/packages/react-reconciler/src/ReactFiberClassComponent.js +++ b/packages/react-reconciler/src/ReactFiberClassComponent.js @@ -44,16 +44,24 @@ let didWarnAboutStateAssignmentForComponent; let warnOnInvalidCallback; if (__DEV__) { + const didWarnOnInvalidCallback = {}; didWarnAboutStateAssignmentForComponent = {}; warnOnInvalidCallback = function(callback: mixed, callerName: string) { - warning( - callback === null || typeof callback === 'function', - '%s(...): Expected the last optional `callback` argument to be a ' + - 'function. Instead received: %s.', - callerName, - callback, - ); + if (callback === null || typeof callback === 'function') { + return; + } + const key = `${callerName}_${(callback: any)}`; + if (!didWarnOnInvalidCallback[key]) { + warning( + false, + '%s(...): Expected the last optional `callback` argument to be a ' + + 'function. Instead received: %s.', + callerName, + callback, + ); + didWarnOnInvalidCallback[key] = true; + } }; // This is so gross but it's at least non-critical and can be removed if