66
* one.
67
*/
68
69
+/**
70
+ * Generate a unique key that identifies this child within a set.
71
+ *
72
+ * @param {*} Manually provided key.
73
+ * @param {number} Index that is used if a manual key is not provided.
74
+ * @param {?number} Grouping index if this is used in a nested array.
75
+ * @return {string}
76
+ */
77
+function createKey(explicitKey, childIndex, groupingIndex) {
78
+ return ReactCurrentOwner.getDepth() + ':' +
79
+ (groupingIndex == null ? '' : groupingIndex + ':') +
80
+ (explicitKey == null ? '' + childIndex : explicitKey);
81
+}
82
+
83
+/**
84
+ * Returns true if this parameter type is considered an empty child slot.
85
+ * Used to filter out empty slots and generate a compact array.
86
+ *
87
+ * @param {*} Child component or any value.
88
+ * @return {boolean}
89
+ */
90
function isEmptyChild(child) {
91
return child == null || typeof child === 'boolean';
92
}
93
73
-function assignKey(setKey, child, index) {
74
- if (ReactComponent.isValidComponent(child)) {
94
+/**
95
+ * Assign an internal identity to a child component.
96
+ *
97
+ * @param {number} Index of the current array grouping.
98
+ * @param {*} Child component or any value.
99
+ * @param {number} Index of the current child within it's grouping.
100
+ */
101
+function assignKey(groupingIndex, child, index) {
102
+ // Only truthy internal keys are valid. If it's not, we assign one.
103
+ if (ReactComponent.isValidComponent(child) && !child._key) {
104
var key = child.props.key;
105
if (__DEV__) {
77
- if (!HAS_WARNED && !key) {
106
+ // This is in an array. This could grow and shrink or be reordered.
107
+ // All children that doesn't already have autogenerated identity needs
108
+ // to have an explicit key provided.
109
+ if (!HAS_WARNED && key == null) {
110
HAS_WARNED = true;
111
console && console.warn && console.warn(CHILD_HAS_NO_IDENTITY);
112
}
113
}
82
- child._key = (setKey ? setKey + ':' : '') + (key || ('' + index));
114
+ child._key = createKey(key, index, groupingIndex);
115
}
116
}
117
118
+/**
119
+ * Make sure all children have an internal identity. Returns true if this is
120
+ * already a compact array.
121
+ *
122
+ * @param {array} Children of any type.
123
+ * @return {boolean}
124
+ */
125
function tryToReuseArray(children) {
126
for (var i = 0; i < children.length; i++) {
127
var child = children[i];
128
if (isEmptyChild(child)) return false;
90
- assignKey('0', child, i);
129
+ assignKey(0, child, i);
130
}
131
return true;
132
}
133
95
-function appendNestedChildren(parentKey, sourceArray, targetArray) {
134
+/**
135
+ * Append children from the source array to the target array. Make sure all
136
+ * children have an internal identity assigned to it based on insertion point.
137
+ *
138
+ * @param {number} Index of the current array grouping.
139
+ * @param {array} Source array.
140
+ * @param {array} Target array that will be appended to.
141
+ */
142
+function appendNestedChildren(groupingIndex, sourceArray, targetArray) {
143
for (var i = 0; i < sourceArray.length; i++) {
144
var child = sourceArray[i];
145
if (isEmptyChild(child)) continue;
99
- assignKey(parentKey, child, i);
146
+ assignKey(groupingIndex, child, i);
147
// TODO: Invalid components like strings could possibly need
148
// keys assigned to them here. Usually they're not stateful but
149
// CSS transitions and special events could make them stateful.
341
if (child.length === 0) continue;
342
343
if (targetArray === null) targetArray = [];
297
- appendNestedChildren('' + (i - 1), child, targetArray);
344
+ appendNestedChildren(i - 1, child, targetArray);
345
346
} else if (!isEmptyChild(child)) {
347
301
- if (ReactComponent.isValidComponent(child)) {
348
+ // Only truthy internal keys are valid. If it's not, we assign one.
349
+ if (ReactComponent.isValidComponent(child) && !child._key) {
350
// This is a static node and therefore safe to key by index.
351
// No warning necessary.
304
- child._key = child.props.key || ('' + (i - 1));
352
+ child._key = createKey(child.props.key, i - 1);
353
}
354
355
if (targetArray === null) targetArray = [];