Skip to content

Commit f5bb22f

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 177cd85 commit f5bb22f

File tree

5 files changed

+58
-22
lines changed

5 files changed

+58
-22
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 didWarnAboutNoopUpdateForComponent = {};
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 componentName =
180+
(constructor && getComponentName(constructor)) || 'ReactClass';
181+
const warningKey = `${callerName}_${componentName}`;
182+
if (didWarnAboutNoopUpdateForComponent[warningKey]) {
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+
componentName,
186194
);
195+
didWarnAboutNoopUpdateForComponent[warningKey] = true;
187196
}
188197
}
189198

packages/react-reconciler/src/ReactFiberClassComponent.js

Lines changed: 12 additions & 7 deletions
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 didWarnAboutStateAssignmentForComponent = {};
4445

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

394395
if (instance.state !== oldState) {
395396
if (__DEV__) {
396-
warning(
397-
false,
398-
'%s.componentWillReceiveProps(): Assigning directly to ' +
399-
"this.state is deprecated (except inside a component's " +
400-
'constructor). Use setState instead.',
401-
getComponentName(workInProgress),
402-
);
397+
const componentName = getComponentName(workInProgress) || 'Component';
398+
if (!didWarnAboutStateAssignmentForComponent[componentName]) {
399+
warning(
400+
false,
401+
'%s.componentWillReceiveProps(): Assigning directly to ' +
402+
"this.state is deprecated (except inside a component's " +
403+
'constructor). Use setState instead.',
404+
componentName,
405+
);
406+
didWarnAboutStateAssignmentForComponent[componentName] = true;
407+
}
403408
}
404409
updater.enqueueReplaceState(instance, instance.state, null);
405410
}

packages/react-reconciler/src/ReactFiberScheduler.js

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

103103
var didWarnAboutStateTransition = false;
104+
var didWarnSetStateChildContext = false;
105+
var didWarnStateUpdateForUnmountedComponent = {};
106+
107+
var warnAboutUpdateOnUnmounted = function(fiber: Fiber) {
108+
const componentName = getComponentName(fiber) || 'ReactClass';
109+
if (didWarnStateUpdateForUnmountedComponent[componentName]) {
110+
return;
111+
}
104112

105-
var warnAboutUpdateOnUnmounted = function(
106-
instance: React$ComponentType<any>,
107-
) {
108-
const ctor = instance.constructor;
109113
warning(
110114
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',
115+
'Can only update a mounted or mounting ' +
116+
'component. This usually means you called setState, replaceState, ' +
117+
'or forceUpdate on an unmounted component. This is a no-op.\n\nPlease ' +
118+
'check the code for the %s component.',
119+
componentName,
116120
);
121+
didWarnStateUpdateForUnmountedComponent[componentName] = true;
117122
};
118123

119124
var warnAboutInvalidUpdates = function(instance: React$ComponentType<any>) {
120125
switch (ReactDebugCurrentFiber.phase) {
121126
case 'getChildContext':
127+
if (didWarnSetStateChildContext) {
128+
return;
129+
}
122130
warning(
123131
false,
124132
'setState(...): Cannot call setState() inside getChildContext()',
125133
);
134+
didWarnSetStateChildContext = true;
126135
break;
127136
case 'render':
128137
if (didWarnAboutStateTransition) {
129138
return;
130139
}
131-
didWarnAboutStateTransition = true;
132140
warning(
133141
false,
134142
'Cannot update during an existing state transition (such as within ' +
135143
"`render` or another component's constructor). Render methods should " +
136144
'be a pure function of props and state; constructor side-effects are ' +
137145
'an anti-pattern, but can be moved to `componentWillMount`.',
138146
);
147+
didWarnAboutStateTransition = true;
139148
break;
140149
}
141150
};
@@ -1229,7 +1238,7 @@ module.exports = function<T, P, I, TI, PI, C, CC, CX, PL>(
12291238
} else {
12301239
if (__DEV__) {
12311240
if (!isErrorRecovery && fiber.tag === ClassComponent) {
1232-
warnAboutUpdateOnUnmounted(fiber.stateNode);
1241+
warnAboutUpdateOnUnmounted(fiber);
12331242
}
12341243
}
12351244
return;

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: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,21 +9,29 @@
99

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

1415
function warnNoop(publicInstance, callerName) {
1516
if (__DEV__) {
1617
var constructor = publicInstance.constructor;
18+
const componentName =
19+
(constructor && (constructor.displayName || constructor.name)) ||
20+
'ReactClass';
21+
const warningKey = `${callerName}_${componentName}`;
22+
if (didWarnStateUpdateForUnmountedComponent[warningKey]) {
23+
return;
24+
}
1725
warning(
1826
false,
1927
'%s(...): Can only update a mounted or mounting component. ' +
2028
'This usually means you called %s() on an unmounted component. ' +
2129
'This is a no-op.\n\nPlease check the code for the %s component.',
2230
callerName,
2331
callerName,
24-
(constructor && (constructor.displayName || constructor.name)) ||
25-
'ReactClass',
32+
componentName,
2633
);
34+
didWarnStateUpdateForUnmountedComponent[warningKey] = true;
2735
}
2836
}
2937

0 commit comments

Comments
 (0)