@samitouri / QOS-React-2 / commits / 64c9d9d762

Split out warning message for nested key warning

Also make sure to mark child array as validated in cloneElement as well.

Ben Alpert committed May 12, 2015 at 16:33 UTC 64c9d9d7629600da81ceefcaa59c46e64d030874
3 files changed +38 -27
src/classic/element/ReactElement.js
+19 -15
@@ -80,6 +80,21 @@ function defineMutationMembrane(prototype) {
80 }
81 }
82
83 +function markChildArrayValidated(childArray) {
84 + // To make comparing ReactElements easier for testing purposes, we make the
85 + // validation flag non-enumerable (where possible, which should include every
86 + // environment we run tests in), so the test framework ignores it.
87 + try {
88 + Object.defineProperty(childArray, '_reactChildKeysValidated', {
89 + configurable: false,
90 + enumerable: false,
91 + writable: true
92 + });
93 + } catch (x) {
94 + }
95 + childArray._reactChildKeysValidated = true;
96 +}
97 +
98 /**
99 * Base constructor for all React elements. This is only used to make this
100 * work with a dynamic instanceof check. Nothing should live on this prototype.
@@ -156,23 +171,9 @@ ReactElement.createElement = function(type, config, children) {
171 props.children = children;
172 } else if (childrenLength > 1) {
173 var childArray = Array(childrenLength);
159 -
174 if (__DEV__) {
161 - // To make comparing ReactElements easier for testing purposes, we make
162 - // the validation flag non-enumerable (where possible, which should
163 - // include every environment we run tests in), so the test framework
164 - // ignores it.
165 - try {
166 - Object.defineProperty(childArray, '_reactChildKeysValidated', {
167 - configurable: false,
168 - enumerable: false,
169 - writable: true
170 - });
171 - } catch (x) {
172 - }
173 - childArray._reactChildKeysValidated = true;
175 + markChildArrayValidated(childArray);
176 }
175 -
177 for (var i = 0; i < childrenLength; i++) {
178 childArray[i] = arguments[i + 2];
179 }
@@ -260,6 +261,9 @@ ReactElement.cloneElement = function(element, config, children) {
261 props.children = children;
262 } else if (childrenLength > 1) {
263 var childArray = Array(childrenLength);
264 + if (__DEV__) {
265 + markChildArrayValidated(childArray);
266 + }
267 for (var i = 0; i < childrenLength; i++) {
268 childArray[i] = arguments[i + 2];
269 }
src/classic/element/ReactElementValidator.js
+17 -10
@@ -90,13 +90,19 @@ function getCurrentOwnerDisplayName() {
90 * @internal
91 * @param {ReactElement} element Element that requires a key.
92 * @param {*} parentType element's parent's type.
93 + * @param {boolean} deep false if top-level collection, true if nested
94 */
94 -function validateExplicitKey(element, parentType) {
95 +function validateExplicitKey(element, parentType, deep) {
96 if (element.key != null) {
97 return;
98 }
99 warnAndMonitorForKeyUse(
99 - 'Each child in an array or iterator should have a unique "key" prop.',
100 + // We vary the message for nested key warning to allow filtering them out
101 + // since we didn't historically warn in this case.
102 + deep ?
103 + 'Each child in a nested array or iterator should have ' +
104 + 'a unique "key" prop.' :
105 + 'Each child in an array or iterator should have a unique "key" prop.',
106 element,
107 parentType
108 );
@@ -178,8 +184,9 @@ function warnAndMonitorForKeyUse(message, element, parentType) {
184 * @internal
185 * @param {ReactNode} node Statically passed child of any type.
186 * @param {*} parentType node's parent's type.
187 + * @param {boolean} deep false if top-level collection, true if nested
188 */
182 -function validateChildKeys(node, parentType) {
189 +function validateChildKeys(node, parentType, deep) {
190 if (Array.isArray(node)) {
191 if (node._reactChildKeysValidated) {
192 // All child elements were passed in a valid location.
@@ -188,10 +195,10 @@ function validateChildKeys(node, parentType) {
195 for (var i = 0; i < node.length; i++) {
196 var child = node[i];
197 if (ReactElement.isValidElement(child)) {
191 - validateExplicitKey(child, parentType);
198 + validateExplicitKey(child, parentType, deep);
199 } else {
200 // TODO: Warn on unkeyed arrays and suggest using createFragment
194 - validateChildKeys(child, parentType);
201 + validateChildKeys(child, parentType, true);
202 }
203 }
204 } else if (
@@ -209,9 +216,9 @@ function validateChildKeys(node, parentType) {
216 var step;
217 while (!(step = iterator.next()).done) {
218 if (ReactElement.isValidElement(step.value)) {
212 - validateExplicitKey(step.value, parentType);
219 + validateExplicitKey(step.value, parentType, deep);
220 } else {
214 - validateChildKeys(step.value, parentType);
221 + validateChildKeys(step.value, parentType, true);
222 }
223 }
224 }
@@ -220,7 +227,7 @@ function validateChildKeys(node, parentType) {
227 for (var key in fragment) {
228 if (fragment.hasOwnProperty(key)) {
229 validatePropertyKey(key, fragment[key], parentType);
223 - validateChildKeys(fragment[key], parentType);
230 + validateChildKeys(fragment[key], parentType, true);
231 }
232 }
233 }
@@ -426,7 +433,7 @@ var ReactElementValidator = {
433 }
434
435 for (var i = 2; i < arguments.length; i++) {
429 - validateChildKeys(arguments[i], type);
436 + validateChildKeys(arguments[i], type, false);
437 }
438
439 validatePropTypes(element);
@@ -474,7 +481,7 @@ var ReactElementValidator = {
481 cloneElement: function(element, props, children) {
482 var newElement = ReactElement.cloneElement.apply(this, arguments);
483 for (var i = 2; i < arguments.length; i++) {
477 - validateChildKeys(arguments[i], newElement.type);
484 + validateChildKeys(arguments[i], newElement.type, false);
485 }
486 validatePropTypes(newElement);
487 return newElement;
src/classic/element/__tests__/ReactElementValidator-test.js
+2 -2
@@ -134,8 +134,8 @@ describe('ReactElementValidator', function() {
134
135 expect(console.error.argsForCall.length).toBe(1);
136 expect(console.error.argsForCall[0][0]).toBe(
137 - 'Warning: Each child in an array or iterator should have a unique ' +
138 - '"key" prop. Check the React.render call using <div>. See ' +
137 + 'Warning: Each child in a nested array or iterator should have a ' +
138 + 'unique "key" prop. Check the React.render call using <div>. See ' +
139 'https://fb.me/react-warning-keys for more information.'
140 );
141 });