diff --git a/src/core/ReactComponent.js b/src/core/ReactComponent.js
index d380e943c3..bc3769df92 100644
--- a/src/core/ReactComponent.js
+++ b/src/core/ReactComponent.js
@@ -235,6 +235,14 @@ var ReactComponent = {
* @public
*/
replaceProps: function(props) {
+ invariant(
+ !this.props[OWNER],
+ 'replaceProps(...): You called `setProps` or `replaceProps` on a ' +
+ 'component with an owner. 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.'
+ );
var transaction = ReactComponent.ReactReconcileTransaction.getPooled();
transaction.perform(this.receiveProps, this, props, transaction);
ReactComponent.ReactReconcileTransaction.release(transaction);
diff --git a/src/core/__tests__/ReactComponentLifeCycle-test.js b/src/core/__tests__/ReactComponentLifeCycle-test.js
index 7fbbbcd56c..4c1f92e465 100644
--- a/src/core/__tests__/ReactComponentLifeCycle-test.js
+++ b/src/core/__tests__/ReactComponentLifeCycle-test.js
@@ -375,6 +375,34 @@ describe('ReactComponentLifeCycle', function() {
expect(instance.state).toEqual(POST_WILL_UNMOUNT_STATE);
});
+ it('should throw when calling setProps() on an owned component', function() {
+ /**
+ * calls setProps in an componentDidMount.
+ */
+ var PropsUpdaterInOnDOMReady = React.createClass({
+ componentDidMount: function() {
+ this.refs.theSimpleComponent.setProps({
+ value: this.props.valueToUseInOnDOMReady
+ });
+ },
+ render: function() {
+ return (
+
+
+ );
+ }
+ });
+ var instance =
+ ;
+ expect(ReactTestUtils.renderIntoDocument.bind(ReactTestUtils, instance))
+ .toThrow();
+ });
+
it('should allow state updates in componentDidMount', function() {
/**
* calls setState in an componentDidMount.