93
let ownerHasKeyUseWarning;
94
let ownerHasFunctionTypeWarning;
95
let ownerHasSymbolTypeWarning;
96
-let warnForMissingKey = (child: mixed, returnFiber: Fiber) => {};
96
+let warnForMissingKey = (
97
+ returnFiber: Fiber,
98
+ workInProgress: Fiber,
99
+ child: mixed,
100
+) => {};
101
102
if (__DEV__) {
103
didWarnAboutMaps = false;
112
ownerHasFunctionTypeWarning = ({}: {[string]: boolean});
113
ownerHasSymbolTypeWarning = ({}: {[string]: boolean});
114
111
- warnForMissingKey = (child: mixed, returnFiber: Fiber) => {
115
+ warnForMissingKey = (
116
+ returnFiber: Fiber,
117
+ workInProgress: Fiber,
118
+ child: mixed,
119
+ ) => {
120
if (child === null || typeof child !== 'object') {
121
return;
122
}
180
}
181
}
182
175
- // We create a fake Fiber for the child to log the stack trace from.
176
- // TODO: Refactor the warnForMissingKey calls to happen after fiber creation
177
- // so that we can get access to the fiber that will eventually be created.
178
- // That way the log can show up associated with the right instance in DevTools.
179
- const fiber = createFiberFromElement((child: any), returnFiber.mode, 0);
180
- fiber.return = returnFiber;
181
-
182
- runWithFiberInDEV(fiber, () => {
183
+ runWithFiberInDEV(workInProgress, () => {
184
console.error(
185
'Each child in a list should have a unique "key" prop.' +
186
'%s%s See https://react.dev/link/warning-keys for more information.',
1035
* Warns if there is a duplicate or missing key
1036
*/
1037
function warnOnInvalidKey(
1038
+ returnFiber: Fiber,
1039
+ workInProgress: Fiber,
1040
child: mixed,
1041
knownKeys: Set<string> | null,
1039
- returnFiber: Fiber,
1042
): Set<string> | null {
1043
if (__DEV__) {
1044
if (typeof child !== 'object' || child === null) {
1047
switch (child.$$typeof) {
1048
case REACT_ELEMENT_TYPE:
1049
case REACT_PORTAL_TYPE:
1048
- warnForMissingKey(child, returnFiber);
1050
+ warnForMissingKey(returnFiber, workInProgress, child);
1051
const key = child.key;
1052
if (typeof key !== 'string') {
1053
break;
1061
knownKeys.add(key);
1062
break;
1063
}
1062
- console.error(
1063
- 'Encountered two children with the same key, `%s`. ' +
1064
- 'Keys should be unique so that components maintain their identity ' +
1065
- 'across updates. Non-unique keys may cause children to be ' +
1066
- 'duplicated and/or omitted — the behavior is unsupported and ' +
1067
- 'could change in a future version.',
1068
- key,
1069
- );
1064
+ runWithFiberInDEV(workInProgress, () => {
1065
+ console.error(
1066
+ 'Encountered two children with the same key, `%s`. ' +
1067
+ 'Keys should be unique so that components maintain their identity ' +
1068
+ 'across updates. Non-unique keys may cause children to be ' +
1069
+ 'duplicated and/or omitted — the behavior is unsupported and ' +
1070
+ 'could change in a future version.',
1071
+ key,
1072
+ );
1073
+ });
1074
break;
1075
case REACT_LAZY_TYPE: {
1076
let resolvedChild;
1081
const init = (child._init: any);
1082
resolvedChild = init(payload);
1083
}
1080
- warnOnInvalidKey(resolvedChild, knownKeys, returnFiber);
1084
+ warnOnInvalidKey(
1085
+ returnFiber,
1086
+ workInProgress,
1087
+ resolvedChild,
1088
+ knownKeys,
1089
+ );
1090
break;
1091
}
1092
default:
1122
// If you change this code, also update reconcileChildrenIterator() which
1123
// uses the same algorithm.
1124
1116
- if (__DEV__) {
1117
- // First, validate keys.
1118
- let knownKeys: Set<string> | null = null;
1119
- for (let i = 0; i < newChildren.length; i++) {
1120
- const child = newChildren[i];
1121
- knownKeys = warnOnInvalidKey(child, knownKeys, returnFiber);
1122
- }
1123
- }
1125
+ let knownKeys: Set<string> | null = null;
1126
1127
let resultingFirstChild: Fiber | null = null;
1128
let previousNewFiber: Fiber | null = null;
1155
}
1156
break;
1157
}
1158
+
1159
+ if (__DEV__) {
1160
+ knownKeys = warnOnInvalidKey(
1161
+ returnFiber,
1162
+ newFiber,
1163
+ newChildren[newIdx],
1164
+ knownKeys,
1165
+ );
1166
+ }
1167
+
1168
if (shouldTrackSideEffects) {
1169
if (oldFiber && newFiber.alternate === null) {
1170
// We matched the slot, but we didn't reuse the existing fiber, so we
1210
if (newFiber === null) {
1211
continue;
1212
}
1213
+ if (__DEV__) {
1214
+ knownKeys = warnOnInvalidKey(
1215
+ returnFiber,
1216
+ newFiber,
1217
+ newChildren[newIdx],
1218
+ knownKeys,
1219
+ );
1220
+ }
1221
lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, newIdx);
1222
if (previousNewFiber === null) {
1223
// TODO: Move out of the loop. This only happens for the first run.
1248
debugInfo,
1249
);
1250
if (newFiber !== null) {
1251
+ if (__DEV__) {
1252
+ knownKeys = warnOnInvalidKey(
1253
+ returnFiber,
1254
+ newFiber,
1255
+ newChildren[newIdx],
1256
+ knownKeys,
1257
+ );
1258
+ }
1259
if (shouldTrackSideEffects) {
1260
if (newFiber.alternate !== null) {
1261
// The new fiber is a work in progress, but if there exists a
1438
let knownKeys: Set<string> | null = null;
1439
1440
let step = newChildren.next();
1413
- if (__DEV__) {
1414
- knownKeys = warnOnInvalidKey(step.value, knownKeys, returnFiber);
1415
- }
1441
for (
1442
;
1443
oldFiber !== null && !step.done;
1419
- newIdx++,
1420
- step = newChildren.next(),
1421
- knownKeys = __DEV__
1422
- ? warnOnInvalidKey(step.value, knownKeys, returnFiber)
1423
- : null
1444
+ newIdx++, step = newChildren.next()
1445
) {
1446
if (oldFiber.index > newIdx) {
1447
nextOldFiber = oldFiber;
1466
}
1467
break;
1468
}
1469
+
1470
+ if (__DEV__) {
1471
+ knownKeys = warnOnInvalidKey(
1472
+ returnFiber,
1473
+ newFiber,
1474
+ step.value,
1475
+ knownKeys,
1476
+ );
1477
+ }
1478
+
1479
if (shouldTrackSideEffects) {
1480
if (oldFiber && newFiber.alternate === null) {
1481
// We matched the slot, but we didn't reuse the existing fiber, so we
1511
if (oldFiber === null) {
1512
// If we don't have any more existing children we can choose a fast path
1513
// since the rest will all be insertions.
1483
- for (
1484
- ;
1485
- !step.done;
1486
- newIdx++,
1487
- step = newChildren.next(),
1488
- knownKeys = __DEV__
1489
- ? warnOnInvalidKey(step.value, knownKeys, returnFiber)
1490
- : null
1491
- ) {
1514
+ for (; !step.done; newIdx++, step = newChildren.next()) {
1515
const newFiber = createChild(returnFiber, step.value, lanes, debugInfo);
1516
if (newFiber === null) {
1517
continue;
1518
}
1519
+ if (__DEV__) {
1520
+ knownKeys = warnOnInvalidKey(
1521
+ returnFiber,
1522
+ newFiber,
1523
+ step.value,
1524
+ knownKeys,
1525
+ );
1526
+ }
1527
lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, newIdx);
1528
if (previousNewFiber === null) {
1529
// TODO: Move out of the loop. This only happens for the first run.
1544
const existingChildren = mapRemainingChildren(oldFiber);
1545
1546
// Keep scanning and use the map to restore deleted items as moves.
1516
- for (
1517
- ;
1518
- !step.done;
1519
- newIdx++,
1520
- step = newChildren.next(),
1521
- knownKeys = __DEV__
1522
- ? warnOnInvalidKey(step.value, knownKeys, returnFiber)
1523
- : null
1524
- ) {
1547
+ for (; !step.done; newIdx++, step = newChildren.next()) {
1548
const newFiber = updateFromMap(
1549
existingChildren,
1550
returnFiber,
1554
debugInfo,
1555
);
1556
if (newFiber !== null) {
1557
+ if (__DEV__) {
1558
+ knownKeys = warnOnInvalidKey(
1559
+ returnFiber,
1560
+ newFiber,
1561
+ step.value,
1562
+ knownKeys,
1563
+ );
1564
+ }
1565
if (shouldTrackSideEffects) {
1566
if (newFiber.alternate !== null) {
1567
// The new fiber is a work in progress, but if there exists a