@samitouri / QOS-React-2 / commits / 216fcdeb42

Ignore children with clashing keys

Fixes #566.

Ben Alpert committed Apr 6, 2014 at 20:47 UTC 216fcdeb42cd4d783a89f618ed989010c10506fc
3 files changed +29 -20
src/utils/ReactChildren.js
+13 -8
@@ -20,8 +20,8 @@
20
21 var PooledClass = require('PooledClass');
22
23 -var invariant = require('invariant');
23 var traverseAllChildren = require('traverseAllChildren');
24 +var warning = require('warning');
25
26 var twoArgumentPooler = PooledClass.twoArgumentPooler;
27 var threeArgumentPooler = PooledClass.threeArgumentPooler;
@@ -86,16 +86,21 @@ PooledClass.addPoolingTo(MapBookKeeping, threeArgumentPooler);
86 function mapSingleChildIntoContext(traverseContext, child, name, i) {
87 var mapBookKeeping = traverseContext;
88 var mapResult = mapBookKeeping.mapResult;
89 - var mappedChild =
90 - mapBookKeeping.mapFunction.call(mapBookKeeping.mapContext, child, i);
91 - // We found a component instance
92 - invariant(
93 - !mapResult.hasOwnProperty(name),
89 +
90 + var keyUnique = !mapResult.hasOwnProperty(name);
91 + warning(
92 + keyUnique,
93 'ReactChildren.map(...): Encountered two children with the same key, ' +
95 - '`%s`. Children keys must be unique.',
94 + '`%s`. Child keys must be unique; when two children share a key, only ' +
95 + 'the first child will be used.',
96 name
97 );
98 - mapResult[name] = mappedChild;
98 +
99 + if (keyUnique) {
100 + var mappedChild =
101 + mapBookKeeping.mapFunction.call(mapBookKeeping.mapContext, child, i);
102 + mapResult[name] = mappedChild;
103 + }
104 }
105
106 /**
src/utils/__tests__/ReactChildren-test.js
+8 -6
@@ -320,17 +320,19 @@ describe('ReactChildren', function() {
320 }).not.toThrow();
321 });
322
323 - it('should throw if key provided is a dupe with explicit key', function() {
323 + it('should warn if key provided is a dupe with explicit key', function() {
324 var zero = <div key="something"/>;
325 - var one = <div key="something" />;
325 + var one = <span key="something" />;
326
327 - var mapFn = function() {return null;};
327 + var mapFn = function(component) { return component; };
328 var instance = (
329 <div>{zero}{one}</div>
330 );
331
332 - expect(function() {
333 - ReactChildren.map(instance.props.children, mapFn);
334 - }).toThrow();
332 + spyOn(console, 'warn');
333 + var mapped = ReactChildren.map(instance.props.children, mapFn);
334 +
335 + expect(console.warn.calls.length).toEqual(1);
336 + expect(mapped).toEqual({'.$something': zero});
337 });
338 });
src/utils/flattenChildren.js
+8 -6
@@ -18,8 +18,8 @@
18
19 "use strict";
20
21 -var invariant = require('invariant');
21 var traverseAllChildren = require('traverseAllChildren');
22 +var warning = require('warning');
23
24 /**
25 * @param {function} traverseContext Context passed through traversal.
@@ -29,13 +29,15 @@ var traverseAllChildren = require('traverseAllChildren');
29 function flattenSingleChildIntoContext(traverseContext, child, name) {
30 // We found a component instance.
31 var result = traverseContext;
32 - invariant(
33 - !result.hasOwnProperty(name),
34 - 'flattenChildren(...): Encountered two children with the same key, `%s`. ' +
35 - 'Children keys must be unique.',
32 + var keyUnique = !result.hasOwnProperty(name);
33 + warning(
34 + keyUnique,
35 + 'flattenChildren(...): Encountered two children with the same key, ' +
36 + '`%s`. Child keys must be unique; when two children share a key, only ' +
37 + 'the first child will be used.',
38 name
39 );
38 - if (child != null) {
40 + if (keyUnique && child != null) {
41 result[name] = child;
42 }
43 }