Skip to content

Commit 4a100f8

Browse files
committed
Deduplicated many warnings (#11140)
* Deduplicated the following warnings: 1. 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 2. %s.componentWillReceiveProps(): Assigning directly to this.state is deprecated (except inside a component's constructor). Use setState instead.' 3. 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. 4. setState(...): Cannot call setState() inside getChildContext() * Code review changes made for #11140
1 parent 84a2891 commit 4a100f8

File tree

5 files changed

+55
-12
lines changed

5 files changed

+55
-12
lines changed

packages/react-dom/src/server/ReactPartialRenderer.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ if (__DEV__) {
7272
var {ReactDebugCurrentFrame} = require('shared/ReactGlobalSharedState');
7373
var currentDebugStack = null;
7474
var currentDebugElementStack = null;
75+
var errorInfo = {};
7576
var setCurrentDebugStack = function(stack: Array<Frame>) {
7677
var frame: Frame = stack[stack.length - 1];
7778
currentDebugElementStack = ((frame: any): FrameDev).debugElementStack;
@@ -175,15 +176,23 @@ function warnNoop(
175176
) {
176177
if (__DEV__) {
177178
var constructor = publicInstance.constructor;
179+
const currentComponent =
180+
(constructor && getComponentName(constructor)) || 'ReactClass';
181+
const currentComponentError = `${callerName}_${currentComponent}`;
182+
if (errorInfo[currentComponentError]) {
183+
return;
184+
}
185+
178186
warning(
179187
false,
180188
'%s(...): Can only update a mounting component. ' +
181189
'This usually means you called %s() outside componentWillMount() on the server. ' +
182190
'This is a no-op.\n\nPlease check the code for the %s component.',
183191
callerName,
184192
callerName,
185-
(constructor && getComponentName(constructor)) || 'ReactClass',
193+
currentComponent,
186194
);
195+
errorInfo[currentComponentError] = true;
187196
}
188197
}
189198

packages/react-reconciler/src/ReactFiberClassComponent.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ if (__DEV__) {
4141
var warning = require('fbjs/lib/warning');
4242

4343
var {startPhaseTimer, stopPhaseTimer} = require('./ReactDebugFiberPerf');
44+
var stateDeprecationWarning = {};
4445

4546
var warnOnInvalidCallback = function(callback: mixed, callerName: string) {
4647
warning(
@@ -393,13 +394,19 @@ module.exports = function(
393394

394395
if (instance.state !== oldState) {
395396
if (__DEV__) {
397+
const currentComponent =
398+
getComponentName(workInProgress) || 'Component';
399+
if (stateDeprecationWarning[currentComponent]) {
400+
return;
401+
}
396402
warning(
397403
false,
398404
'%s.componentWillReceiveProps(): Assigning directly to ' +
399405
"this.state is deprecated (except inside a component's " +
400406
'constructor). Use setState instead.',
401-
getComponentName(workInProgress),
407+
currentComponent,
402408
);
409+
stateDeprecationWarning[currentComponent] = true;
403410
}
404411
updater.enqueueReplaceState(instance, instance.state, null);
405412
}

packages/react-reconciler/src/ReactFiberScheduler.js

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -101,41 +101,54 @@ if (__DEV__) {
101101
} = require('./ReactDebugFiberPerf');
102102

103103
var didWarnAboutStateTransition = false;
104+
var didWarnSetStateChildContext = false;
105+
var ownerHasNoopWarning = {};
104106

105107
var warnAboutUpdateOnUnmounted = function(
106108
instance: React$ComponentType<any>,
107109
) {
108-
const ctor = instance.constructor;
110+
const ctor: Object = instance.constructor;
111+
const currentComponent =
112+
(ctor && (ctor.displayName || ctor.name)) || 'ReactClass';
113+
if (ownerHasNoopWarning[currentComponent]) {
114+
return;
115+
}
116+
109117
warning(
110118
false,
111-
'Can only update a mounted or mounting component. This usually means ' +
112-
'you called setState, replaceState, or forceUpdate on an unmounted ' +
113-
'component. This is a no-op.\n\nPlease check the code for the ' +
114-
'%s component.',
115-
(ctor && (ctor.displayName || ctor.name)) || 'ReactClass',
119+
'Can only update a mounted or mounting ' +
120+
'component. This usually means you called setState, replaceState, ' +
121+
'or forceUpdate on an unmounted component. This is a no-op.\n\nPlease ' +
122+
'check the code for the %s component.',
123+
currentComponent,
116124
);
125+
ownerHasNoopWarning[currentComponent] = true;
117126
};
118127

119128
var warnAboutInvalidUpdates = function(instance: React$ComponentType<any>) {
120129
switch (ReactDebugCurrentFiber.phase) {
121130
case 'getChildContext':
131+
if (didWarnSetStateChildContext) {
132+
return;
133+
}
122134
warning(
123135
false,
124136
'setState(...): Cannot call setState() inside getChildContext()',
125137
);
138+
didWarnSetStateChildContext = true;
126139
break;
127140
case 'render':
128141
if (didWarnAboutStateTransition) {
129142
return;
130143
}
131-
didWarnAboutStateTransition = true;
132144
warning(
133145
false,
134146
'Cannot update during an existing state transition (such as within ' +
135147
"`render` or another component's constructor). Render methods should " +
136148
'be a pure function of props and state; constructor side-effects are ' +
137149
'an anti-pattern, but can be moved to `componentWillMount`.',
138150
);
151+
didWarnAboutStateTransition = true;
139152
break;
140153
}
141154
};

packages/react-reconciler/src/ReactFiberUpdateQueue.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ const {NoWork} = require('./ReactFiberExpirationTime');
2020

2121
if (__DEV__) {
2222
var warning = require('fbjs/lib/warning');
23+
var didWarnUpdateInsideUpdate = false;
2324
}
2425

2526
type PartialState<State, Props> =
@@ -132,14 +133,18 @@ function insertUpdateIntoFiber<State>(
132133

133134
// Warn if an update is scheduled from inside an updater function.
134135
if (__DEV__) {
135-
if (queue1.isProcessing || (queue2 !== null && queue2.isProcessing)) {
136+
if (
137+
(queue1.isProcessing || (queue2 !== null && queue2.isProcessing)) &&
138+
!didWarnUpdateInsideUpdate
139+
) {
136140
warning(
137141
false,
138142
'An update (setState, replaceState, or forceUpdate) was scheduled ' +
139143
'from inside an update function. Update functions should be pure, ' +
140144
'with zero side-effects. Consider using componentDidUpdate or a ' +
141145
'callback.',
142146
);
147+
didWarnUpdateInsideUpdate = true;
143148
}
144149
}
145150

packages/react/src/ReactNoopUpdateQueue.js

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,21 +9,30 @@
99

1010
if (__DEV__) {
1111
var warning = require('fbjs/lib/warning');
12+
var errorInfo = {};
1213
}
1314

1415
function warnNoop(publicInstance, callerName) {
1516
if (__DEV__) {
1617
var constructor = publicInstance.constructor;
18+
const currentComponent =
19+
(constructor && (constructor.displayName || constructor.name)) ||
20+
'ReactClass';
21+
const currentComponentError = `${callerName}_${currentComponent}`;
22+
if (errorInfo[currentComponentError]) {
23+
return;
24+
}
25+
1726
warning(
1827
false,
1928
'%s(...): Can only update a mounted or mounting component. ' +
2029
'This usually means you called %s() on an unmounted component. ' +
2130
'This is a no-op.\n\nPlease check the code for the %s component.',
2231
callerName,
2332
callerName,
24-
(constructor && (constructor.displayName || constructor.name)) ||
25-
'ReactClass',
33+
currentComponent,
2634
);
35+
errorInfo[currentComponentError] = true;
2736
}
2837
}
2938

0 commit comments

Comments
 (0)