diff --git a/src/browser/server/ReactServerRendering.js b/src/browser/server/ReactServerRendering.js index d29989e0cb710..fb5c45c37bd6f 100644 --- a/src/browser/server/ReactServerRendering.js +++ b/src/browser/server/ReactServerRendering.js @@ -40,7 +40,7 @@ function renderToString(element, context) { return transaction.perform(function() { var componentInstance = instantiateReactComponent(element, null); - var markup = componentInstance.mountComponent(id, transaction, 0, context); + var markup = componentInstance.mountComponent(id, transaction, context); return ReactMarkupChecksum.addChecksumToMarkup(markup); }, null); } finally { @@ -68,7 +68,7 @@ function renderToStaticMarkup(element, context) { return transaction.perform(function() { var componentInstance = instantiateReactComponent(element, null); - return componentInstance.mountComponent(id, transaction, 0, context); + return componentInstance.mountComponent(id, transaction, context); }, null); } finally { ReactServerRenderingTransaction.release(transaction); diff --git a/src/browser/ui/ReactDOMComponent.js b/src/browser/ui/ReactDOMComponent.js index 5216a530e2d2f..42a044d15d10a 100644 --- a/src/browser/ui/ReactDOMComponent.js +++ b/src/browser/ui/ReactDOMComponent.js @@ -168,15 +168,13 @@ ReactDOMComponent.Mixin = { * @internal * @param {string} rootID The root DOM ID for this node. * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction - * @param {number} mountDepth number of components in the owner hierarchy * @return {string} The computed markup. */ - mountComponent: function(rootID, transaction, mountDepth, context) { + mountComponent: function(rootID, transaction, context) { ReactComponent.Mixin.mountComponent.call( this, rootID, transaction, - mountDepth, context ); this._rootNodeID = rootID; diff --git a/src/browser/ui/ReactDOMTextComponent.js b/src/browser/ui/ReactDOMTextComponent.js index 54e5c7acf2e9e..e12ee2753a950 100644 --- a/src/browser/ui/ReactDOMTextComponent.js +++ b/src/browser/ui/ReactDOMTextComponent.js @@ -62,11 +62,10 @@ assign(ReactDOMTextComponent.prototype, { * * @param {string} rootID DOM ID of the root node. * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction - * @param {number} mountDepth number of components in the owner hierarchy * @return {string} Markup for this text node. * @internal */ - mountComponent: function(rootID, transaction, mountDepth, context) { + mountComponent: function(rootID, transaction, context) { this._rootNodeID = rootID; var escapedText = escapeTextForBrowser(this._stringText); diff --git a/src/browser/ui/ReactMount.js b/src/browser/ui/ReactMount.js index 90a874622d748..218a020667d5c 100644 --- a/src/browser/ui/ReactMount.js +++ b/src/browser/ui/ReactMount.js @@ -225,7 +225,8 @@ function mountComponentIntoNode( container, transaction, shouldReuseMarkup) { - var markup = this.mountComponent(rootID, transaction, 0, emptyObject); + var markup = this.mountComponent(rootID, transaction, emptyObject); + this._isTopLevel = true; ReactMount._mountImageIntoNode(markup, container, shouldReuseMarkup); } diff --git a/src/browser/ui/__tests__/ReactDOMComponent-test.js b/src/browser/ui/__tests__/ReactDOMComponent-test.js index 5427b832ba327..7bb8e24650216 100644 --- a/src/browser/ui/__tests__/ReactDOMComponent-test.js +++ b/src/browser/ui/__tests__/ReactDOMComponent-test.js @@ -328,7 +328,7 @@ describe('ReactDOMComponent', function() { _owner: null, _context: null }); - return stubComponent.mountComponent('test', transaction, 0, {}); + return stubComponent.mountComponent('test', transaction, {}); }; }); diff --git a/src/browser/ui/dom/__tests__/Danger-test.js b/src/browser/ui/dom/__tests__/Danger-test.js index 1e2e6f02d338e..69f71c4655e80 100644 --- a/src/browser/ui/dom/__tests__/Danger-test.js +++ b/src/browser/ui/dom/__tests__/Danger-test.js @@ -32,7 +32,7 @@ describe('Danger', function() { it('should render markup', function() { var markup = instantiateReactComponent(
- ).mountComponent('.rX', transaction, 0, {}); + ).mountComponent('.rX', transaction, {}); var output = Danger.dangerouslyRenderMarkup([markup])[0]; expect(output.nodeName).toBe('DIV'); @@ -44,7 +44,7 @@ describe('Danger', function() { ).mountComponent( '.rX', transaction, - 0, {} + {} ); var output = Danger.dangerouslyRenderMarkup([markup])[0]; @@ -55,7 +55,7 @@ describe('Danger', function() { it('should render wrapped markup', function() { var markup = instantiateReactComponent( - ).mountComponent('.rX', transaction, 0, {}); + ).mountComponent('.rX', transaction, {}); var output = Danger.dangerouslyRenderMarkup([markup])[0]; expect(output.nodeName).toBe('TH'); diff --git a/src/core/ReactComponent.js b/src/core/ReactComponent.js index f9361bac20350..694d9578dd171 100644 --- a/src/core/ReactComponent.js +++ b/src/core/ReactComponent.js @@ -90,7 +90,6 @@ var ReactComponent = { // to track updates. this._currentElement = element; this._mountIndex = 0; - this._mountDepth = 0; }, /** @@ -103,17 +102,15 @@ var ReactComponent = { * * @param {string} rootID DOM ID of the root node. * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction - * @param {number} mountDepth number of components in the owner hierarchy. * @return {?string} Rendered markup to be inserted into the DOM. * @internal */ - mountComponent: function(rootID, transaction, mountDepth, context) { + mountComponent: function(rootID, transaction, context) { var ref = this._currentElement.ref; if (ref != null) { var owner = this._currentElement._owner; attachRef(ref, this, owner); } - this._mountDepth = mountDepth; // Effectively: return ''; }, diff --git a/src/core/ReactCompositeComponent.js b/src/core/ReactCompositeComponent.js index bb43da310f1f5..192de12e4eb87 100644 --- a/src/core/ReactCompositeComponent.js +++ b/src/core/ReactCompositeComponent.js @@ -141,6 +141,7 @@ var ReactCompositeComponentMixin = assign({}, this._context = null; this._mountOrder = 0; + this._isTopLevel = false; // See ReactUpdates. this._pendingCallbacks = null; @@ -161,17 +162,15 @@ var ReactCompositeComponentMixin = assign({}, * * @param {string} rootID DOM ID of the root node. * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction - * @param {number} mountDepth number of components in the owner hierarchy * @return {?string} Rendered markup to be inserted into the DOM. * @final * @internal */ - mountComponent: function(rootID, transaction, mountDepth, context) { + mountComponent: function(rootID, transaction, context) { ReactComponent.Mixin.mountComponent.call( this, rootID, transaction, - mountDepth, context ); @@ -233,7 +232,6 @@ var ReactCompositeComponentMixin = assign({}, var markup = this._renderedComponent.mountComponent( rootID, transaction, - mountDepth + 1, this._processChildContext(context) ); if (inst.componentDidMount) { @@ -313,7 +311,7 @@ var ReactCompositeComponentMixin = assign({}, */ replaceProps: function(props, callback) { invariant( - this._mountDepth === 0, + this._isTopLevel, 'replaceProps(...): You called `setProps` or `replaceProps` on a ' + 'component with a parent. This is an anti-pattern since props will ' + 'get reactively updated when rendered. Instead, change the owner\'s ' + @@ -781,7 +779,6 @@ var ReactCompositeComponentMixin = assign({}, var nextMarkup = this._renderedComponent.mountComponent( thisID, transaction, - this._mountDepth + 1, context ); ReactComponentEnvironment.replaceNodeWithMarkupByID( @@ -890,17 +887,15 @@ var ShallowMixin = assign({}, * * @param {string} rootID DOM ID of the root node. * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction - * @param {number} mountDepth number of components in the owner hierarchy * @return {ReactElement} Shallow rendering of the component. * @final * @internal */ - mountComponent: function(rootID, transaction, mountDepth, context) { + mountComponent: function(rootID, transaction, context) { ReactComponent.Mixin.mountComponent.call( this, rootID, transaction, - mountDepth, context ); diff --git a/src/core/ReactMultiChild.js b/src/core/ReactMultiChild.js index a6314fa87128c..15cf15b73fefe 100644 --- a/src/core/ReactMultiChild.js +++ b/src/core/ReactMultiChild.js @@ -195,7 +195,6 @@ var ReactMultiChild = { var mountImage = childInstance.mountComponent( rootID, transaction, - this._mountDepth + 1, context ); childInstance._mountIndex = index; @@ -401,7 +400,6 @@ var ReactMultiChild = { var mountImage = child.mountComponent( rootID, transaction, - this._mountDepth + 1, context ); child._mountIndex = index; diff --git a/src/core/__tests__/ReactComponent-test.js b/src/core/__tests__/ReactComponent-test.js index 3b09fb2f52870..31b15549c84f5 100644 --- a/src/core/__tests__/ReactComponent-test.js +++ b/src/core/__tests__/ReactComponent-test.js @@ -16,7 +16,6 @@ var ReactInstanceMap; var ReactTestUtils; var reactComponentExpect; -var getMountDepth; describe('ReactComponent', function() { beforeEach(function() { @@ -24,10 +23,6 @@ describe('ReactComponent', function() { ReactInstanceMap = require('ReactInstanceMap'); ReactTestUtils = require('ReactTestUtils'); reactComponentExpect = require('reactComponentExpect'); - - getMountDepth = function(instance) { - return ReactInstanceMap.get(instance)._mountDepth; - }; }); it('should throw on invalid render targets', function() { @@ -231,80 +226,4 @@ describe('ReactComponent', function() { var instance = ReactTestUtils.renderIntoDocument(element); expect(instance.isMounted()).toBeTruthy(); }); - - it('should know its simple mount depth', function() { - var Owner = React.createClass({ - render: function() { - return ; - } - }); - - var Child = React.createClass({ - render: function() { - return
; - } - }); - - var instance = ; - instance = ReactTestUtils.renderIntoDocument(instance); - expect(getMountDepth(instance)).toBe(0); - expect(getMountDepth(instance.refs.child)).toBe(1); - }); - - it('should know its (complicated) mount depth', function() { - var Box = React.createClass({ - render: function() { - return
{this.props.children}
; - } - }); - - var Child = React.createClass({ - render: function() { - return child; - } - }); - - var Switcher = React.createClass({ - getInitialState: function() { - return {tabKey: 'hello'}; - }, - - render: function() { - var child = this.props.children; - - return ( - -
- {child} -
-
- ); - } - }); - - var App = React.createClass({ - render: function() { - return ( - - - - ); - } - }); - - var root = ; - root = ReactTestUtils.renderIntoDocument(root); - - expect(getMountDepth(root)).toBe(0); - expect(getMountDepth(root.refs.switcher)).toBe(1); - expect(getMountDepth(root.refs.switcher.refs.box)).toBe(2); - expect(getMountDepth(root.refs.switcher.refs.switcherDiv)).toBe(5); - expect(getMountDepth(root.refs.child)).toBe(7); - expect(getMountDepth(root.refs.switcher.refs.box.refs.boxDiv)).toBe(3); - expect(getMountDepth(root.refs.child.refs.span)).toBe(8); - }); }); diff --git a/src/core/__tests__/ReactCompositeComponent-test.js b/src/core/__tests__/ReactCompositeComponent-test.js index a8e41988cb9f8..c31c88d462253 100644 --- a/src/core/__tests__/ReactCompositeComponent-test.js +++ b/src/core/__tests__/ReactCompositeComponent-test.js @@ -529,6 +529,34 @@ describe('ReactCompositeComponent', function() { ); }); + it('should only allow `setProps` on top-level components', function() { + var container = document.createElement('div'); + document.documentElement.appendChild(container); + + var innerInstance; + + var Component = React.createClass({ + render: function() { + return
; + }, + componentDidMount: function() { + innerInstance = this.refs.inner; + } + }); + React.render(, container); + + expect(innerInstance).not.toBe(undefined); + expect(function() { + innerInstance.setProps({value: 1}); + }).toThrow( + 'Invariant Violation: replaceProps(...): You called `setProps` or ' + + '`replaceProps` on a component with a parent. This is an anti-pattern ' + + 'since props will get reactively updated when rendered. Instead, ' + + 'change the owner\'s `render` method to pass the correct value as ' + + 'props to the component where it is created.' + ); + }); + it('should cleanup even if render() fatals', function() { var BadComponent = React.createClass({ render: function() { diff --git a/src/test/ReactTestUtils.js b/src/test/ReactTestUtils.js index 9b148d188f531..8871a8c12ca29 100644 --- a/src/test/ReactTestUtils.js +++ b/src/test/ReactTestUtils.js @@ -340,7 +340,7 @@ ReactShallowRenderer.prototype._render = function(element, transaction, context) var instance = new ShallowComponentWrapper(new element.type(element.props)); instance.construct(element); - instance.mountComponent(rootID, transaction, 0, context); + instance.mountComponent(rootID, transaction, context); this._instance = instance; } else {