diff --git a/src/class/ReactClass.js b/src/class/ReactClass.js index bae11f56219..b38bc4c72ce 100644 --- a/src/class/ReactClass.js +++ b/src/class/ReactClass.js @@ -22,7 +22,6 @@ var invariant = require('invariant'); var keyMirror = require('keyMirror'); var keyOf = require('keyOf'); var monitorCodeUse = require('monitorCodeUse'); -var mapObject = require('mapObject'); var warning = require('warning'); var MIXINS_KEY = keyOf({mixins: null}); @@ -566,24 +565,26 @@ function mixStaticSpecIntoComponent(Constructor, statics) { * @param {object} two The second object * @return {object} one after it has been mutated to contain everything in two. */ -function mergeObjectsWithNoDuplicateKeys(one, two) { +function mergeIntoWithNoDuplicateKeys(one, two) { invariant( one && two && typeof one === 'object' && typeof two === 'object', - 'mergeObjectsWithNoDuplicateKeys(): Cannot merge non-objects' + 'mergeIntoWithNoDuplicateKeys(): Cannot merge non-objects.' ); - mapObject(two, function(value, key) { - invariant( - one[key] === undefined, - 'mergeObjectsWithNoDuplicateKeys(): ' + - 'Tried to merge two objects with the same key: `%s`. This conflict ' + - 'may be due to a mixin; in particular, this may be caused by two ' + - 'getInitialState() or getDefaultProps() methods returning objects ' + - 'with clashing keys.', - key - ); - one[key] = value; - }); + for (var key in two) { + if (two.hasOwnProperty(key)) { + invariant( + one[key] === undefined, + 'mergeIntoWithNoDuplicateKeys(): ' + + 'Tried to merge two objects with the same key: `%s`. This conflict ' + + 'may be due to a mixin; in particular, this may be caused by two ' + + 'getInitialState() or getDefaultProps() methods returning objects ' + + 'with clashing keys.', + key + ); + one[key] = two[key]; + } + } return one; } @@ -604,7 +605,10 @@ function createMergedResultFunction(one, two) { } else if (b == null) { return a; } - return mergeObjectsWithNoDuplicateKeys(a, b); + var c = {}; + mergeIntoWithNoDuplicateKeys(c, a); + mergeIntoWithNoDuplicateKeys(c, b); + return c; }; } diff --git a/src/core/__tests__/ReactCompositeComponent-test.js b/src/core/__tests__/ReactCompositeComponent-test.js index 1510af60113..a8e41988cb9 100644 --- a/src/core/__tests__/ReactCompositeComponent-test.js +++ b/src/core/__tests__/ReactCompositeComponent-test.js @@ -586,7 +586,7 @@ describe('ReactCompositeComponent', function() { expect(function() { instance = ReactTestUtils.renderIntoDocument(instance); }).toThrow( - 'Invariant Violation: mergeObjectsWithNoDuplicateKeys(): ' + + 'Invariant Violation: mergeIntoWithNoDuplicateKeys(): ' + 'Tried to merge two objects with the same key: `x`. This conflict ' + 'may be due to a mixin; in particular, this may be caused by two ' + 'getInitialState() or getDefaultProps() methods returning objects ' + @@ -594,6 +594,26 @@ describe('ReactCompositeComponent', function() { ); }); + it('should not mutate objects returned by getInitialState()', function() { + var Mixin = { + getInitialState: function() { + return Object.freeze({mixin: true}); + } + }; + var Component = React.createClass({ + mixins: [Mixin], + getInitialState: function() { + return Object.freeze({component: true}); + }, + render: function() { + return ; + } + }); + expect(() => { + ReactTestUtils.renderIntoDocument(); + }).not.toThrow(); + }); + it('should work with object getInitialState() return values', function() { var Component = React.createClass({ getInitialState: function() {