diff --git a/src/core/ReactComponent.js b/src/core/ReactComponent.js index 5c42a8e86f..bc3769df92 100644 --- a/src/core/ReactComponent.js +++ b/src/core/ReactComponent.js @@ -72,7 +72,7 @@ function isEmptyChild(child) { function assignKey(setKey, child, index) { if (ReactComponent.isValidComponent(child)) { - var key = child._key || child.props.key; + var key = child.props.key; if (__DEV__) { if (!HAS_WARNED && !key) { HAS_WARNED = true; @@ -300,7 +300,7 @@ var ReactComponent = { } else if (!isEmptyChild(child)) { - if (ReactComponent.isValidComponent(child) && !child._key) { + if (ReactComponent.isValidComponent(child)) { // This is a static node and therefore safe to key by index. // No warning necessary. child._key = child.props.key || ('' + (i - 1)); diff --git a/src/core/__tests__/ReactIdentity-test.js b/src/core/__tests__/ReactIdentity-test.js index ecf71a8553..e21be9d3bb 100644 --- a/src/core/__tests__/ReactIdentity-test.js +++ b/src/core/__tests__/ReactIdentity-test.js @@ -80,4 +80,75 @@ describe('ReactIdentity', function() { .toEqual('.reactRoot[0].:2.:chipmunk'); }); + it('should let restructured components retain their uniqueness', function() { + var instance0 = ; + var instance1 = ; + var instance2 = ; + var wrapped =
{instance0} {instance1}
; + var unwrappedAndAdded = +
+ {instance2} + {wrapped.props.children[0]} + {wrapped.props.children[1]} +
; + + expect(function() { + + React.renderComponent(unwrappedAndAdded, document.createElement('div')); + + }).not.toThrow(); + }); + + it('should retain keys during updates in composite components', function() { + + var TestComponent = React.createClass({ + render: function() { + return
{this.props.children}
; + } + }); + + var TestContainer = React.createClass({ + + getInitialState: function() { + return { swapped: false }; + }, + + swap: function() { + this.setState({ swapped: true }); + }, + + render: function() { + return ( + + {this.state.swapped ? this.props.second : this.props.first} + {this.state.swapped ? this.props.first : this.props.second} + + ); + } + + }); + + var instance0 = ; + var instance1 = ; + + var wrapped = ; + + React.renderComponent(wrapped, document.createElement('div')); + + var beforeKey = wrapped + ._renderedComponent + ._renderedComponent + .props.children[0]._key; + + wrapped.swap(); + + var afterKey = wrapped + ._renderedComponent + ._renderedComponent + .props.children[0]._key; + + expect(beforeKey).not.toEqual(afterKey); + + }); + }); diff --git a/src/utils/mapChildren.js b/src/utils/mapChildren.js index cdba3e4d90..27079e8930 100644 --- a/src/utils/mapChildren.js +++ b/src/utils/mapChildren.js @@ -26,7 +26,7 @@ function mapChildren(children, mapFunction, context) { var child = children[ii]; var key = child._key; var mappedChild = mapFunction.call(context, child, key, ii); - mappedChild._key = key; + mappedChild.props.key = key; mappedChildren.push(mappedChild); } return mappedChildren;