Better warnings for missing keys on arrays

We have less dynamic arrays in the code base now so let's start warning for all
the cases where we pass dynamic arrays without keys.

I use the displayName to point out which component's render method was
responsible. I only warn once per component. If the child was created in a
different component (and passed as a property) I also show the owner of the
child. Maybe it should've attached the key at a higher level.

This does give false positives for arrays that are truly static. Those should
probably be refactored to use the XML syntax if possible.
This commit is contained in:
CommitSyncScript
2013-06-18 09:31:42 -07:00
committed by Paul O’Shannessy
parent 37ddfa0521
commit 0e91febb9c

View File

@@ -58,10 +58,12 @@ var ComponentLifeCycle = keyMirror({
*/
var CHILD_HAS_NO_IDENTITY =
'You are passing a dynamic array of children. You should set the ' +
'property "key" to a string that uniquely identifies each child.';
'Each child in an array should have a unique "key" prop. ' +
'Check the render method of ';
var HAS_WARNED = false;
var CHILD_CAME_FROM_ANOTHER_OWNER = '. It was passed a child from ';
var owner_has_warned = {};
/**
* Helpers for flattening child arguments onto a new array or use an existing
@@ -108,9 +110,28 @@ function assignKey(groupingIndex, child, index) {
// This is in an array. This could grow and shrink or be reordered.
// All children that doesn't already have autogenerated identity needs
// to have an explicit key provided.
if (!HAS_WARNED && key == null) {
HAS_WARNED = true;
console && console.warn && console.warn(CHILD_HAS_NO_IDENTITY);
if (key == null) {
// Name of the component whose render method tried to pass children.
var currentName =
ReactCurrentOwner.current &&
ReactCurrentOwner.current.constructor.displayName;
// Name of the component that originally created this child.
var childOwnerName =
child.props[OWNER] && child.props[OWNER].constructor.displayName;
if (currentName && !owner_has_warned.hasOwnProperty(currentName)) {
owner_has_warned[currentName] = true;
var message = CHILD_HAS_NO_IDENTITY + currentName;
if (childOwnerName && currentName !== childOwnerName) {
// Usually the current owner is the offender, but if it accepts
// children as a property, it may be the creator of the child that's
// responsible for assigning it a key.
message += CHILD_CAME_FROM_ANOTHER_OWNER + childOwnerName;
}
message += '.';
console && console.warn && console.warn(message);
}
}
}
child._key = createKey(key, index, groupingIndex);