@samitouri / QOS-React-2 / commits / d0883c8cc7

Use depth (not owner) to check for root components

Fixes #557.

Ben Alpert committed Nov 17, 2013 at 13:38 UTC d0883c8cc74ba7253123cfe482ad993647b6693a
2 files changed +56 -8
src/core/ReactComponent.js
+6 -6
@@ -260,17 +260,17 @@ var ReactComponent = {
260 */
261 replaceProps: function(props, callback) {
262 invariant(
263 - !this._owner,
263 + this.isMounted(),
264 + 'replaceProps(...): Can only update a mounted component.'
265 + );
266 + invariant(
267 + this._mountDepth === 0,
268 'replaceProps(...): You called `setProps` or `replaceProps` on a ' +
265 - 'component with an owner. This is an anti-pattern since props will ' +
269 + 'component with a parent. This is an anti-pattern since props will ' +
270 'get reactively updated when rendered. Instead, change the owner\'s ' +
271 '`render` method to pass the correct value as props to the component ' +
272 'where it is created.'
273 );
270 - invariant(
271 - this.isMounted(),
272 - 'replaceProps(...): Can only update a mounted component.'
273 - );
274 this._pendingProps = props;
275 ReactUpdates.enqueueUpdate(this, callback);
276 },
src/core/__tests__/ReactComponentLifeCycle-test.js
+50 -2
@@ -404,8 +404,56 @@ describe('ReactComponentLifeCycle', function() {
404 valueToUseInitially="hello"
405 valueToUseInOnDOMReady="goodbye"
406 />;
407 - expect(ReactTestUtils.renderIntoDocument.bind(ReactTestUtils, instance))
408 - .toThrow();
407 + expect(function() {
408 + ReactTestUtils.renderIntoDocument(instance)
409 + }).toThrow(
410 + 'Invariant Violation: replaceProps(...): You called `setProps` or ' +
411 + '`replaceProps` on a component with a parent. This is an anti-pattern ' +
412 + 'since props will get reactively updated when rendered. Instead, ' +
413 + 'change the owner\'s `render` method to pass the correct value as ' +
414 + 'props to the component where it is created.'
415 + );
416 + });
417 +
418 + it('should not throw when updating an auxiliary component', function() {
419 + var Tooltip = React.createClass({
420 + render: function() {
421 + return <div>{this.props.children}</div>;
422 + },
423 + componentDidMount: function() {
424 + this.container = document.createElement('div');
425 + this.updateTooltip();
426 + },
427 + componentDidUpdate: function() {
428 + this.updateTooltip();
429 + },
430 + updateTooltip: function() {
431 + // Even though this.props.tooltip has an owner, updating it shouldn't
432 + // throw here because it's mounted as a root component
433 + React.renderComponent(this.props.tooltip, this.container);
434 + }
435 + });
436 + var Component = React.createClass({
437 + render: function() {
438 + return (
439 + <Tooltip
440 + ref="tooltip"
441 + tooltip={<div>{this.props.tooltipText}</div>}>
442 + {this.props.text}
443 + </Tooltip>
444 + );
445 + }
446 + });
447 +
448 + var container = document.createElement('div');
449 + var instance = React.renderComponent(
450 + <Component text="uno" tooltipText="one" />,
451 + container
452 + );
453 +
454 + // Since `instance` is a root component, we can set its props. This also
455 + // makes Tooltip rerender the tooltip component, which shouldn't throw.
456 + instance.setProps({text: "dos", tooltipText: "two"});
457 });
458
459 it('should throw when calling setProps() on an unmounted component',