33
REACT_LAZY_TYPE,
34
REACT_CONTEXT_TYPE,
35
} from 'shared/ReactSymbols';
36
-import {HostRoot, HostText, HostPortal, Fragment} from './ReactWorkTags';
36
+import {
37
+ HostRoot,
38
+ HostText,
39
+ HostPortal,
40
+ Fragment,
41
+ FunctionComponent,
42
+} from './ReactWorkTags';
43
import isArray from 'shared/isArray';
44
import {enableRefAsProp} from 'shared/ReactFeatureFlags';
45
1120
);
1121
}
1122
1123
+ const newChildren = iteratorFn.call(newChildrenIterable);
1124
+
1125
if (__DEV__) {
1118
- // We don't support rendering Generators because it's a mutation.
1119
- // See https://github.com/facebook/react/issues/12995
1120
- if (
1121
- typeof Symbol === 'function' &&
1122
- // $FlowFixMe[prop-missing] Flow doesn't know about toStringTag
1123
- newChildrenIterable[Symbol.toStringTag] === 'Generator'
1124
- ) {
1125
- if (!didWarnAboutGenerators) {
1126
- console.error(
1127
- 'Using Generators as children is unsupported and will likely yield ' +
1128
- 'unexpected results because enumerating a generator mutates it. ' +
1129
- 'You may convert it to an array with `Array.from()` or the ' +
1130
- '`[...spread]` operator before rendering. Keep in mind ' +
1131
- 'you might need to polyfill these features for older browsers.',
1132
- );
1126
+ if (newChildren === newChildrenIterable) {
1127
+ // We don't support rendering Generators as props because it's a mutation.
1128
+ // See https://github.com/facebook/react/issues/12995
1129
+ // We do support generators if they were created by a GeneratorFunction component
1130
+ // as its direct child since we can recreate those by rerendering the component
1131
+ // as needed.
1132
+ const isGeneratorComponent =
1133
+ returnFiber.tag === FunctionComponent &&
1134
+ // $FlowFixMe[method-unbinding]
1135
+ Object.prototype.toString.call(returnFiber.type) ===
1136
+ '[object GeneratorFunction]' &&
1137
+ // $FlowFixMe[method-unbinding]
1138
+ Object.prototype.toString.call(newChildren) === '[object Generator]';
1139
+ if (!isGeneratorComponent) {
1140
+ if (!didWarnAboutGenerators) {
1141
+ console.error(
1142
+ 'Using Iterators as children is unsupported and will likely yield ' +
1143
+ 'unexpected results because enumerating a generator mutates it. ' +
1144
+ 'You may convert it to an array with `Array.from()` or the ' +
1145
+ '`[...spread]` operator before rendering. You can also use an ' +
1146
+ 'Iterable that can iterate multiple times over the same items.',
1147
+ );
1148
+ }
1149
+ didWarnAboutGenerators = true;
1150
}
1134
- didWarnAboutGenerators = true;
1135
- }
1136
-
1137
- // Warn about using Maps as children
1138
- if ((newChildrenIterable: any).entries === iteratorFn) {
1151
+ } else if ((newChildrenIterable: any).entries === iteratorFn) {
1152
+ // Warn about using Maps as children
1153
if (!didWarnAboutMaps) {
1154
console.error(
1155
'Using Maps as children is not supported. ' +
1156
'Use an array of keyed ReactElements instead.',
1157
);
1144
- }
1145
- didWarnAboutMaps = true;
1146
- }
1147
-
1148
- // First, validate keys.
1149
- // We'll get a different iterator later for the main pass.
1150
- const newChildren = iteratorFn.call(newChildrenIterable);
1151
- if (newChildren) {
1152
- let knownKeys: Set<string> | null = null;
1153
- let step = newChildren.next();
1154
- for (; !step.done; step = newChildren.next()) {
1155
- const child = step.value;
1156
- knownKeys = warnOnInvalidKey(child, knownKeys, returnFiber);
1158
+ didWarnAboutMaps = true;
1159
}
1160
}
1161
}
1162
1161
- const newChildren = iteratorFn.call(newChildrenIterable);
1162
-
1163
if (newChildren == null) {
1164
throw new Error('An iterable object provided no iterator.');
1165
}
1172
let newIdx = 0;
1173
let nextOldFiber = null;
1174
1175
+ let knownKeys: Set<string> | null = null;
1176
+
1177
let step = newChildren.next();
1178
+ if (__DEV__) {
1179
+ knownKeys = warnOnInvalidKey(step.value, knownKeys, returnFiber);
1180
+ }
1181
for (
1182
;
1183
oldFiber !== null && !step.done;
1179
- newIdx++, step = newChildren.next()
1184
+ newIdx++,
1185
+ step = newChildren.next(),
1186
+ knownKeys = __DEV__
1187
+ ? warnOnInvalidKey(step.value, knownKeys, returnFiber)
1188
+ : null
1189
) {
1190
if (oldFiber.index > newIdx) {
1191
nextOldFiber = oldFiber;
1245
if (oldFiber === null) {
1246
// If we don't have any more existing children we can choose a fast path
1247
// since the rest will all be insertions.
1239
- for (; !step.done; newIdx++, step = newChildren.next()) {
1248
+ for (
1249
+ ;
1250
+ !step.done;
1251
+ newIdx++,
1252
+ step = newChildren.next(),
1253
+ knownKeys = __DEV__
1254
+ ? warnOnInvalidKey(step.value, knownKeys, returnFiber)
1255
+ : null
1256
+ ) {
1257
const newFiber = createChild(returnFiber, step.value, lanes, debugInfo);
1258
if (newFiber === null) {
1259
continue;
1278
const existingChildren = mapRemainingChildren(oldFiber);
1279
1280
// Keep scanning and use the map to restore deleted items as moves.
1264
- for (; !step.done; newIdx++, step = newChildren.next()) {
1281
+ for (
1282
+ ;
1283
+ !step.done;
1284
+ newIdx++,
1285
+ step = newChildren.next(),
1286
+ knownKeys = __DEV__
1287
+ ? warnOnInvalidKey(step.value, knownKeys, returnFiber)
1288
+ : null
1289
+ ) {
1290
const newFiber = updateFromMap(
1291
existingChildren,
1292
returnFiber,