Ignore children with clashing keys

Fixes #566.
This commit is contained in:
Ben Alpert
2014-04-07 13:50:42 -07:00
parent 21de5c816f
commit 216fcdeb42
3 changed files with 29 additions and 20 deletions
+13 -8
View File
@@ -20,8 +20,8 @@
var PooledClass = require('PooledClass');
var invariant = require('invariant');
var traverseAllChildren = require('traverseAllChildren');
var warning = require('warning');
var twoArgumentPooler = PooledClass.twoArgumentPooler;
var threeArgumentPooler = PooledClass.threeArgumentPooler;
@@ -86,16 +86,21 @@ PooledClass.addPoolingTo(MapBookKeeping, threeArgumentPooler);
function mapSingleChildIntoContext(traverseContext, child, name, i) {
var mapBookKeeping = traverseContext;
var mapResult = mapBookKeeping.mapResult;
var mappedChild =
mapBookKeeping.mapFunction.call(mapBookKeeping.mapContext, child, i);
// We found a component instance
invariant(
!mapResult.hasOwnProperty(name),
var keyUnique = !mapResult.hasOwnProperty(name);
warning(
keyUnique,
'ReactChildren.map(...): Encountered two children with the same key, ' +
'`%s`. Children keys must be unique.',
'`%s`. Child keys must be unique; when two children share a key, only ' +
'the first child will be used.',
name
);
mapResult[name] = mappedChild;
if (keyUnique) {
var mappedChild =
mapBookKeeping.mapFunction.call(mapBookKeeping.mapContext, child, i);
mapResult[name] = mappedChild;
}
}
/**
+8 -6
View File
@@ -320,17 +320,19 @@ describe('ReactChildren', function() {
}).not.toThrow();
});
it('should throw if key provided is a dupe with explicit key', function() {
it('should warn if key provided is a dupe with explicit key', function() {
var zero = <div key="something"/>;
var one = <div key="something" />;
var one = <span key="something" />;
var mapFn = function() {return null;};
var mapFn = function(component) { return component; };
var instance = (
<div>{zero}{one}</div>
);
expect(function() {
ReactChildren.map(instance.props.children, mapFn);
}).toThrow();
spyOn(console, 'warn');
var mapped = ReactChildren.map(instance.props.children, mapFn);
expect(console.warn.calls.length).toEqual(1);
expect(mapped).toEqual({'.$something': zero});
});
});
+8 -6
View File
@@ -18,8 +18,8 @@
"use strict";
var invariant = require('invariant');
var traverseAllChildren = require('traverseAllChildren');
var warning = require('warning');
/**
* @param {function} traverseContext Context passed through traversal.
@@ -29,13 +29,15 @@ var traverseAllChildren = require('traverseAllChildren');
function flattenSingleChildIntoContext(traverseContext, child, name) {
// We found a component instance.
var result = traverseContext;
invariant(
!result.hasOwnProperty(name),
'flattenChildren(...): Encountered two children with the same key, `%s`. ' +
'Children keys must be unique.',
var keyUnique = !result.hasOwnProperty(name);
warning(
keyUnique,
'flattenChildren(...): Encountered two children with the same key, ' +
'`%s`. Child keys must be unique; when two children share a key, only ' +
'the first child will be used.',
name
);
if (child != null) {
if (keyUnique && child != null) {
result[name] = child;
}
}