diff --git a/src/core/ReactCompositeComponent.js b/src/core/ReactCompositeComponent.js index f6681d44f7..f6af832e67 100644 --- a/src/core/ReactCompositeComponent.js +++ b/src/core/ReactCompositeComponent.js @@ -1164,6 +1164,17 @@ var ReactCompositeComponentMixin = { 'ReactCompositeComponent', '_renderValidatedComponent', function() { + // We set ReactCurrentOwner.current back to null at the end of this + // function, so it should be null right now. If it's not, later code may + // give confusing errors. + invariant( + ReactCurrentOwner.current == null, + '%s.render(): Render methods should be a pure function of props and ' + + 'state; triggering nested component updates from render is not ' + + 'allowed. If necessary, trigger nested updates in ' + + 'componentDidUpdate.', + this.constructor.displayName || 'ReactCompositeComponent' + ); var renderedComponent; var previousContext = ReactContext.current; ReactContext.current = this._processChildContext( diff --git a/src/core/__tests__/ReactCompositeComponent-test.js b/src/core/__tests__/ReactCompositeComponent-test.js index add279580f..6994a7a0b4 100644 --- a/src/core/__tests__/ReactCompositeComponent-test.js +++ b/src/core/__tests__/ReactCompositeComponent-test.js @@ -1345,4 +1345,27 @@ describe('ReactCompositeComponent', function() { expect(console.warn.argsForCall.length).toBe(0); }); + it('should disallow nested render calls', function() { + var Inner = React.createClass({ + render: function() { + return
; + } + }); + var Outer = React.createClass({ + render: function() { + ReactTestUtils.renderIntoDocument(