diff --git a/src/core/ReactCompositeComponent.js b/src/core/ReactCompositeComponent.js
index 788a16bd87..1f6b2a635c 100644
--- a/src/core/ReactCompositeComponent.js
+++ b/src/core/ReactCompositeComponent.js
@@ -623,6 +623,10 @@ var ReactCompositeComponentMixin = {
return inst.state;
}
+ if (replace && queue.length === 1) {
+ return queue[0];
+ }
+
var nextState = assign({}, replace ? queue[0] : inst.state);
for (var i = replace ? 1 : 0; i < queue.length; i++) {
var partial = queue[i];
diff --git a/src/core/__tests__/ReactCompositeComponent-test.js b/src/core/__tests__/ReactCompositeComponent-test.js
index a0e7067a13..20f238fdf4 100644
--- a/src/core/__tests__/ReactCompositeComponent-test.js
+++ b/src/core/__tests__/ReactCompositeComponent-test.js
@@ -877,4 +877,69 @@ describe('ReactCompositeComponent', function() {
expect(console.error.argsForCall.length).toBe(0);
});
+ it('should replace state', function() {
+ var Moo = React.createClass({
+ getInitialState: function() {
+ return {x: 1};
+ },
+ render: function() {
+ return
;
+ }
+ });
+
+ var moo = ReactTestUtils.renderIntoDocument();
+ moo.replaceState({y: 2});
+ expect('x' in moo.state).toBe(false);
+ expect(moo.state.y).toBe(2);
+ });
+
+ it('should support objects with prototypes as state', function() {
+ var NotActuallyImmutable = function(str) {
+ this.str = str;
+ };
+ NotActuallyImmutable.prototype.amIImmutable = function() {
+ return true;
+ };
+ var Moo = React.createClass({
+ getInitialState: function() {
+ return new NotActuallyImmutable('first');
+ },
+ render: function() {
+ return ;
+ }
+ });
+
+ var moo = ReactTestUtils.renderIntoDocument();
+ expect(moo.state.str).toBe('first');
+ expect(moo.state.amIImmutable()).toBe(true);
+
+ var secondState = new NotActuallyImmutable('second');
+ moo.replaceState(secondState);
+ expect(moo.state.str).toBe('second');
+ expect(moo.state.amIImmutable()).toBe(true);
+ expect(moo.state).toBe(secondState);
+
+ moo.setState({str: 'third'});
+ expect(moo.state.str).toBe('third');
+ // Here we lose the prototype.
+ expect(moo.state.amIImmutable).toBe(undefined);
+
+ // When more than one state update is enqueued, we have the same behavior
+ var fifthState = new NotActuallyImmutable('fifth');
+ ReactUpdates.batchedUpdates(function() {
+ moo.setState({str: 'fourth'});
+ moo.replaceState(fifthState);
+ });
+ expect(moo.state).toBe(fifthState);
+
+ // When more than one state update is enqueued, we have the same behavior
+ var sixthState = new NotActuallyImmutable('sixth');
+ ReactUpdates.batchedUpdates(function() {
+ moo.replaceState(sixthState);
+ moo.setState({str: 'seventh'});
+ });
+ expect(moo.state.str).toBe('seventh');
+ expect(moo.state.amIImmutable).toBe(undefined);
+ });
+
});