From 0e91febb9ce8eb6eac3154a6e4b06cfcc16115ab Mon Sep 17 00:00:00 2001 From: CommitSyncScript Date: Tue, 18 Jun 2013 09:31:42 -0700 Subject: [PATCH] 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. --- src/core/ReactComponent.js | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/src/core/ReactComponent.js b/src/core/ReactComponent.js index 67b4e90207..530a6f9c66 100644 --- a/src/core/ReactComponent.js +++ b/src/core/ReactComponent.js @@ -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);