Skip to content

Commit 10f9476

Browse files
committed
Merge pull request facebook#6121 from raineroviir/rainer
Fix facebook#6114 - Calling setState inside getChildContext should warn
2 parents 3b86cb1 + 9c1916d commit 10f9476

File tree

5 files changed

+89
-0
lines changed

5 files changed

+89
-0
lines changed

src/isomorphic/ReactDebugTool.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
'use strict';
1313

14+
var ReactInvalidSetStateWarningDevTool = require('ReactInvalidSetStateWarningDevTool');
1415
var warning = require('warning');
1516

1617
var eventHandlers = [];
@@ -48,6 +49,15 @@ var ReactDebugTool = {
4849
}
4950
}
5051
},
52+
onBeginProcessingChildContext() {
53+
emitEvent('onBeginProcessingChildContext');
54+
},
55+
onEndProcessingChildContext() {
56+
emitEvent('onEndProcessingChildContext');
57+
},
58+
onSetState() {
59+
emitEvent('onSetState');
60+
},
5161
onMountRootComponent(internalInstance) {
5262
emitEvent('onMountRootComponent', internalInstance);
5363
},
@@ -62,4 +72,6 @@ var ReactDebugTool = {
6272
},
6373
};
6474

75+
ReactDebugTool.addDevtool(ReactInvalidSetStateWarningDevTool);
76+
6577
module.exports = ReactDebugTool;
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/**
2+
* Copyright 2016-present, Facebook, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree. An additional grant
7+
* of patent rights can be found in the PATENTS file in the same directory.
8+
*
9+
* @providesModule ReactInvalidSetStateWarningDevTool
10+
*/
11+
12+
'use strict';
13+
14+
var warning = require('warning');
15+
16+
if (__DEV__) {
17+
var processingChildContext = false;
18+
19+
var warnInvalidSetState = function() {
20+
warning(
21+
!processingChildContext,
22+
'setState(...): Cannot call setState() inside getChildContext()'
23+
);
24+
};
25+
}
26+
27+
var ReactInvalidSetStateWarningDevTool = {
28+
onBeginProcessingChildContext() {
29+
processingChildContext = true;
30+
},
31+
onEndProcessingChildContext() {
32+
processingChildContext = false;
33+
},
34+
onSetState() {
35+
warnInvalidSetState();
36+
},
37+
};
38+
39+
module.exports = ReactInvalidSetStateWarningDevTool;

src/isomorphic/modern/class/ReactComponent.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
'use strict';
1313

1414
var ReactNoopUpdateQueue = require('ReactNoopUpdateQueue');
15+
var ReactInstrumentation = require('ReactInstrumentation');
1516

1617
var canDefineProperty = require('canDefineProperty');
1718
var emptyObject = require('emptyObject');
@@ -66,6 +67,7 @@ ReactComponent.prototype.setState = function(partialState, callback) {
6667
'function which returns an object of state variables.'
6768
);
6869
if (__DEV__) {
70+
ReactInstrumentation.debugTool.onSetState();
6971
warning(
7072
partialState != null,
7173
'setState(...): You passed an undefined or null state object; ' +

src/renderers/shared/reconciler/ReactCompositeComponent.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ var ReactCurrentOwner = require('ReactCurrentOwner');
1616
var ReactElement = require('ReactElement');
1717
var ReactErrorUtils = require('ReactErrorUtils');
1818
var ReactInstanceMap = require('ReactInstanceMap');
19+
var ReactInstrumentation = require('ReactInstrumentation');
1920
var ReactNodeTypes = require('ReactNodeTypes');
2021
var ReactPerf = require('ReactPerf');
2122
var ReactPropTypeLocations = require('ReactPropTypeLocations');
@@ -496,7 +497,13 @@ var ReactCompositeComponentMixin = {
496497
_processChildContext: function(currentContext) {
497498
var Component = this._currentElement.type;
498499
var inst = this._instance;
500+
if (__DEV__) {
501+
ReactInstrumentation.debugTool.onBeginProcessingChildContext();
502+
}
499503
var childContext = inst.getChildContext && inst.getChildContext();
504+
if (__DEV__) {
505+
ReactInstrumentation.debugTool.onEndProcessingChildContext();
506+
}
500507
if (childContext) {
501508
invariant(
502509
typeof Component.childContextTypes === 'object',

src/renderers/shared/reconciler/__tests__/ReactCompositeComponent-test.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,35 @@ describe('ReactCompositeComponent', function() {
424424
expect(instance2.state.value).toBe(1);
425425
});
426426

427+
it('should warn about `setState` in getChildContext', function() {
428+
var container = document.createElement('div');
429+
430+
var renderPasses = 0;
431+
432+
var Component = React.createClass({
433+
getInitialState: function() {
434+
return {value: 0};
435+
},
436+
getChildContext: function() {
437+
if (this.state.value === 0) {
438+
this.setState({ value: 1 });
439+
}
440+
},
441+
render: function() {
442+
renderPasses++;
443+
return <div />;
444+
},
445+
});
446+
expect(console.error.calls.length).toBe(0);
447+
var instance = ReactDOM.render(<Component />, container);
448+
expect(renderPasses).toBe(2);
449+
expect(instance.state.value).toBe(1);
450+
expect(console.error.calls.length).toBe(1);
451+
expect(console.error.argsForCall[0][0]).toBe(
452+
'Warning: setState(...): Cannot call setState() inside getChildContext()'
453+
);
454+
});
455+
427456
it('should cleanup even if render() fatals', function() {
428457
var BadComponent = React.createClass({
429458
render: function() {

0 commit comments

Comments
 (0)