diff --git a/src/isomorphic/modern/class/ReactNoopUpdateQueue.js b/src/isomorphic/modern/class/ReactNoopUpdateQueue.js index 5c18b85ea8bcb..8406b396588fc 100644 --- a/src/isomorphic/modern/class/ReactNoopUpdateQueue.js +++ b/src/isomorphic/modern/class/ReactNoopUpdateQueue.js @@ -11,21 +11,35 @@ if (__DEV__) { var warning = require('fbjs/lib/warning'); + var errorInfo = {}; } function warnNoop(publicInstance, callerName) { if (__DEV__) { var constructor = publicInstance.constructor; + const currentComponent = + (constructor && (constructor.displayName || constructor.name)) || + 'ReactClass'; + const currentComponentError = + callerName + + '(...): Can only update a mounted or mounting component. ' + + 'This usually means you called ' + + callerName + + '() on an unmounted component. ' + + 'This is a no-op.\n\nPlease check the code for the ' + + currentComponent + + ' component.'; + warning( - false, + !!errorInfo[currentComponentError], '%s(...): Can only update a mounted or mounting component. ' + 'This usually means you called %s() on an unmounted component. ' + 'This is a no-op.\n\nPlease check the code for the %s component.', callerName, callerName, - (constructor && (constructor.displayName || constructor.name)) || - 'ReactClass', + currentComponent, ); + errorInfo[currentComponentError] = true; } } diff --git a/src/renderers/dom/fiber/wrappers/ReactDOMFiberSelect.js b/src/renderers/dom/fiber/wrappers/ReactDOMFiberSelect.js index d35d0bf179ae8..592348144c505 100644 --- a/src/renderers/dom/fiber/wrappers/ReactDOMFiberSelect.js +++ b/src/renderers/dom/fiber/wrappers/ReactDOMFiberSelect.js @@ -157,13 +157,9 @@ var ReactDOMSelect = { }; if (__DEV__) { - if ( - props.value !== undefined && - props.defaultValue !== undefined && - !didWarnValueDefaultValue - ) { + if (props.value !== undefined && props.defaultValue !== undefined) { warning( - false, + didWarnValueDefaultValue, 'Select elements must be either controlled or uncontrolled ' + '(specify either the value prop, or the defaultValue prop, but not ' + 'both). Decide between using a controlled or uncontrolled select ' + diff --git a/src/renderers/shared/fiber/ReactFiberClassComponent.js b/src/renderers/shared/fiber/ReactFiberClassComponent.js index 0e2182e0fc2b8..37bac202c6732 100644 --- a/src/renderers/shared/fiber/ReactFiberClassComponent.js +++ b/src/renderers/shared/fiber/ReactFiberClassComponent.js @@ -44,6 +44,7 @@ const isArray = Array.isArray; if (__DEV__) { var {startPhaseTimer, stopPhaseTimer} = require('ReactDebugFiberPerf'); var warning = require('fbjs/lib/warning'); + var didWarnStateDeprecation = false; var warnOnInvalidCallback = function(callback: mixed, callerName: string) { warning( callback === null || typeof callback === 'function', @@ -369,12 +370,13 @@ module.exports = function( if (instance.state !== oldState) { if (__DEV__) { warning( - false, + didWarnStateDeprecation, '%s.componentWillReceiveProps(): Assigning directly to ' + "this.state is deprecated (except inside a component's " + 'constructor). Use setState instead.', getComponentName(workInProgress), ); + didWarnStateDeprecation = true; } updater.enqueueReplaceState(instance, instance.state, null); } diff --git a/src/renderers/shared/fiber/ReactFiberScheduler.js b/src/renderers/shared/fiber/ReactFiberScheduler.js index bf026e60f4a11..cebbd154b8747 100644 --- a/src/renderers/shared/fiber/ReactFiberScheduler.js +++ b/src/renderers/shared/fiber/ReactFiberScheduler.js @@ -111,41 +111,52 @@ if (__DEV__) { } = require('ReactDebugFiberPerf'); var didWarnAboutStateTransition = false; + var didWarnSetStateChildContext = false; + var ownerHasNoopWarning = {}; var warnAboutUpdateOnUnmounted = function( instance: React$ComponentType, ) { - const ctor = instance.constructor; + const ctor: Object = instance.constructor; + const currentComponent = + (ctor && (ctor.displayName || ctor.name)) || 'ReactClass'; + const currentComponentErrorInfo = + 'Can only update a mounted or mounting ' + + 'component. This usually means you called setState, replaceState, ' + + 'or forceUpdate on an unmounted component. This is a no-op.\n\nPlease ' + + 'check the code for the ' + + currentComponent + + ' component.'; + warning( - false, - 'Can only update a mounted or mounting component. This usually means ' + - 'you called setState, replaceState, or forceUpdate on an unmounted ' + - 'component. This is a no-op.\n\nPlease check the code for the ' + - '%s component.', - (ctor && (ctor.displayName || ctor.name)) || 'ReactClass', + !!ownerHasNoopWarning[currentComponentErrorInfo], + 'Can only update a mounted or mounting ' + + 'component. This usually means you called setState, replaceState, ' + + 'or forceUpdate on an unmounted component. This is a no-op.\n\nPlease ' + + 'check the code for the %s component.', + currentComponent, ); + ownerHasNoopWarning[currentComponentErrorInfo] = true; }; var warnAboutInvalidUpdates = function(instance: React$ComponentType) { switch (ReactDebugCurrentFiber.phase) { case 'getChildContext': warning( - false, + didWarnSetStateChildContext, 'setState(...): Cannot call setState() inside getChildContext()', ); + didWarnSetStateChildContext = true; break; case 'render': - if (didWarnAboutStateTransition) { - return; - } - didWarnAboutStateTransition = true; warning( - false, + didWarnAboutStateTransition, 'Cannot update during an existing state transition (such as within ' + "`render` or another component's constructor). Render methods should " + 'be a pure function of props and state; constructor side-effects are ' + 'an anti-pattern, but can be moved to `componentWillMount`.', ); + didWarnAboutStateTransition = true; break; } }; diff --git a/src/renderers/shared/fiber/ReactFiberUpdateQueue.js b/src/renderers/shared/fiber/ReactFiberUpdateQueue.js index 045e190efa77e..183620650d93c 100644 --- a/src/renderers/shared/fiber/ReactFiberUpdateQueue.js +++ b/src/renderers/shared/fiber/ReactFiberUpdateQueue.js @@ -22,6 +22,7 @@ const {ClassComponent, HostRoot} = require('ReactTypeOfWork'); const invariant = require('fbjs/lib/invariant'); if (__DEV__) { var warning = require('fbjs/lib/warning'); + var didWarnUpdateInsideUpdate = false; } type PartialState = @@ -197,12 +198,13 @@ function insertUpdate(fiber: Fiber, update: Update): Update | null { if (__DEV__) { if (queue1.isProcessing || (queue2 !== null && queue2.isProcessing)) { warning( - false, + didWarnUpdateInsideUpdate, 'An update (setState, replaceState, or forceUpdate) was scheduled ' + 'from inside an update function. Update functions should be pure, ' + 'with zero side-effects. Consider using componentDidUpdate or a ' + 'callback.', ); + didWarnUpdateInsideUpdate = true; } } diff --git a/src/renderers/shared/server/ReactPartialRenderer.js b/src/renderers/shared/server/ReactPartialRenderer.js index 26ffaef0e3106..5f5bb289de0e7 100644 --- a/src/renderers/shared/server/ReactPartialRenderer.js +++ b/src/renderers/shared/server/ReactPartialRenderer.js @@ -63,6 +63,8 @@ if (__DEV__) { var {ReactDebugCurrentFrame} = require('ReactGlobalSharedState'); var currentDebugStack = null; var currentDebugElementStack = null; + var errorInfo = {}; + var setCurrentDebugStack = function(stack) { currentDebugElementStack = stack[stack.length - 1].debugElementStack; // We are about to enter a new composite stack, reset the array. @@ -164,15 +166,28 @@ function warnNoop( ) { if (__DEV__) { var constructor = publicInstance.constructor; + const currentComponent: string = + (constructor && getComponentName(constructor)) || 'ReactClass'; + const currentComponentError: string = + callerName + + '(...): Can only update a mounting component. ' + + 'This usually means you called ' + + callerName + + '() outside componentWillMount() on the server. ' + + 'This is a no-op.\n\nPlease check the code for the ' + + currentComponent + + ' component.'; + warning( - false, + !!errorInfo[currentComponentError], '%s(...): Can only update a mounting component. ' + 'This usually means you called %s() outside componentWillMount() on the server. ' + 'This is a no-op.\n\nPlease check the code for the %s component.', callerName, callerName, - (constructor && getComponentName(constructor)) || 'ReactClass', + currentComponent, ); + errorInfo[currentComponentError] = true; } }