16
import {
17
IndeterminateComponent,
18
FunctionalComponent,
19
+ FunctionalComponentLazy,
20
ClassComponent,
21
+ ClassComponentLazy,
22
HostRoot,
23
HostComponent,
24
HostText,
25
HostPortal,
26
ForwardRef,
27
+ ForwardRefLazy,
28
Fragment,
29
Mode,
30
ContextProvider,
84
getUnmaskedContext,
85
hasContextChanged as hasLegacyContextChanged,
86
pushContextProvider as pushLegacyContextProvider,
87
+ isContextProvider as isLegacyContextProvider,
88
pushTopLevelContextObject,
89
invalidateContextProvider,
90
} from './ReactFiberContext';
100
resumeMountClassInstance,
101
updateClassInstance,
102
} from './ReactFiberClassComponent';
103
+import {readLazyComponentType} from './ReactFiberLazyComponent';
104
+import {getResultFromResolvedThenable} from 'shared/ReactLazyComponent';
105
+import {resolveLazyComponentTag} from './ReactFiber';
106
107
const ReactCurrentOwner = ReactSharedInternals.ReactCurrentOwner;
108
152
function updateForwardRef(
153
current: Fiber | null,
154
workInProgress: Fiber,
155
+ type: any,
156
+ nextProps: any,
157
renderExpirationTime: ExpirationTime,
158
) {
150
- const render = workInProgress.type.render;
151
- const nextProps = workInProgress.pendingProps;
159
+ const render = type.render;
160
const ref = workInProgress.ref;
161
if (hasLegacyContextChanged()) {
162
// Normally we can bail out on props equality but if context has changed
258
function updateFunctionalComponent(
259
current,
260
workInProgress,
261
+ Component,
262
+ nextProps: any,
263
renderExpirationTime,
264
) {
255
- const fn = workInProgress.type;
256
- const nextProps = workInProgress.pendingProps;
257
- const unmaskedContext = getUnmaskedContext(workInProgress);
265
+ const unmaskedContext = getUnmaskedContext(workInProgress, Component);
266
const context = getMaskedContext(workInProgress, unmaskedContext);
267
268
let nextChildren;
270
if (__DEV__) {
271
ReactCurrentOwner.current = workInProgress;
272
ReactCurrentFiber.setCurrentPhase('render');
265
- nextChildren = fn(nextProps, context);
273
+ nextChildren = Component(nextProps, context);
274
ReactCurrentFiber.setCurrentPhase(null);
275
} else {
268
- nextChildren = fn(nextProps, context);
276
+ nextChildren = Component(nextProps, context);
277
}
278
279
// React DevTools reads this flag.
291
function updateClassComponent(
292
current: Fiber | null,
293
workInProgress: Fiber,
294
+ Component: any,
295
+ nextProps,
296
renderExpirationTime: ExpirationTime,
297
) {
298
// Push context providers early to prevent context stack mismatches.
299
// During mounting we don't know the child context yet as the instance doesn't exist.
300
// We will invalidate the child context in finishClassComponent() right after rendering.
291
- const hasContext = pushLegacyContextProvider(workInProgress);
301
+ let hasContext;
302
+ if (isLegacyContextProvider(Component)) {
303
+ hasContext = true;
304
+ pushLegacyContextProvider(workInProgress);
305
+ } else {
306
+ hasContext = false;
307
+ }
308
prepareToReadContext(workInProgress, renderExpirationTime);
309
310
let shouldUpdate;
313
// In the initial pass we might need to construct the instance.
314
constructClassInstance(
315
workInProgress,
300
- workInProgress.pendingProps,
316
+ Component,
317
+ nextProps,
318
+ renderExpirationTime,
319
+ );
320
+ mountClassInstance(
321
+ workInProgress,
322
+ Component,
323
+ nextProps,
324
renderExpirationTime,
325
);
303
- mountClassInstance(workInProgress, renderExpirationTime);
304
-
326
shouldUpdate = true;
327
} else {
328
// In a resume, we'll already have an instance we can reuse.
329
shouldUpdate = resumeMountClassInstance(
330
workInProgress,
331
+ Component,
332
+ nextProps,
333
renderExpirationTime,
334
);
335
}
337
shouldUpdate = updateClassInstance(
338
current,
339
workInProgress,
340
+ Component,
341
+ nextProps,
342
renderExpirationTime,
343
);
344
}
345
return finishClassComponent(
346
current,
347
workInProgress,
348
+ Component,
349
shouldUpdate,
350
hasContext,
351
renderExpirationTime,
355
function finishClassComponent(
356
current: Fiber | null,
357
workInProgress: Fiber,
358
+ Component: any,
359
shouldUpdate: boolean,
360
hasContext: boolean,
361
renderExpirationTime: ExpirationTime,
368
if (!shouldUpdate && !didCaptureError) {
369
// Context providers should defer to sCU for rendering
370
if (hasContext) {
344
- invalidateContextProvider(workInProgress, false);
371
+ invalidateContextProvider(workInProgress, Component, false);
372
}
373
374
return bailoutOnAlreadyFinishedWork(
378
);
379
}
380
354
- const ctor = workInProgress.type;
381
const instance = workInProgress.stateNode;
382
383
// Rerender
386
if (
387
didCaptureError &&
388
(!enableGetDerivedStateFromCatch ||
363
- typeof ctor.getDerivedStateFromCatch !== 'function')
389
+ typeof Component.getDerivedStateFromCatch !== 'function')
390
) {
391
// If we captured an error, but getDerivedStateFrom catch is not defined,
392
// unmount all the children. componentDidCatch will schedule an update to
439
440
// The context might have changed so we need to recalculate it.
441
if (hasContext) {
416
- invalidateContextProvider(workInProgress, true);
442
+ invalidateContextProvider(workInProgress, Component, true);
443
}
444
445
return workInProgress.child;
594
return null;
595
}
596
597
+function resolveDefaultProps(Component, baseProps) {
598
+ if (Component && Component.defaultProps) {
599
+ // Resolve default props. Taken from ReactElement
600
+ const props = Object.assign({}, baseProps);
601
+ const defaultProps = Component.defaultProps;
602
+ for (let propName in defaultProps) {
603
+ if (props[propName] === undefined) {
604
+ props[propName] = defaultProps[propName];
605
+ }
606
+ }
607
+ return props;
608
+ }
609
+ return baseProps;
610
+}
611
+
612
function mountIndeterminateComponent(
613
current,
614
workInProgress,
615
+ Component,
616
renderExpirationTime,
617
) {
618
invariant(
620
'An indeterminate component should never have mounted. This error is ' +
621
'likely caused by a bug in React. Please file an issue.',
622
);
581
- const fn = workInProgress.type;
623
+
624
const props = workInProgress.pendingProps;
583
- const unmaskedContext = getUnmaskedContext(workInProgress);
625
+ if (
626
+ typeof Component === 'object' &&
627
+ Component !== null &&
628
+ typeof Component.then === 'function'
629
+ ) {
630
+ Component = readLazyComponentType(Component);
631
+ const resolvedTag = (workInProgress.tag = resolveLazyComponentTag(
632
+ workInProgress,
633
+ Component,
634
+ ));
635
+ const resolvedProps = resolveDefaultProps(Component, props);
636
+ switch (resolvedTag) {
637
+ case FunctionalComponentLazy: {
638
+ return updateFunctionalComponent(
639
+ current,
640
+ workInProgress,
641
+ Component,
642
+ resolvedProps,
643
+ renderExpirationTime,
644
+ );
645
+ }
646
+ case ClassComponentLazy: {
647
+ return updateClassComponent(
648
+ current,
649
+ workInProgress,
650
+ Component,
651
+ resolvedProps,
652
+ renderExpirationTime,
653
+ );
654
+ }
655
+ case ForwardRefLazy: {
656
+ return updateForwardRef(
657
+ current,
658
+ workInProgress,
659
+ Component,
660
+ resolvedProps,
661
+ renderExpirationTime,
662
+ );
663
+ }
664
+ default: {
665
+ // This message intentionally doesn't metion ForwardRef because the
666
+ // fact that it's a separate type of work is an implementation detail.
667
+ invariant(
668
+ false,
669
+ 'Element type is invalid. Received a promise that resolves to: %s. ' +
670
+ 'Promise elements must resolve to a class or function.',
671
+ Component,
672
+ );
673
+ }
674
+ }
675
+ }
676
+
677
+ const unmaskedContext = getUnmaskedContext(workInProgress, Component);
678
const context = getMaskedContext(workInProgress, unmaskedContext);
679
680
prepareToReadContext(workInProgress, renderExpirationTime);
682
let value;
683
684
if (__DEV__) {
591
- if (fn.prototype && typeof fn.prototype.render === 'function') {
592
- const componentName = getComponentName(fn) || 'Unknown';
685
+ if (
686
+ Component.prototype &&
687
+ typeof Component.prototype.render === 'function'
688
+ ) {
689
+ const componentName = getComponentName(Component) || 'Unknown';
690
691
if (!didWarnAboutBadClass[componentName]) {
692
warningWithoutStack(
705
}
706
707
ReactCurrentOwner.current = workInProgress;
611
- value = fn(props, context);
708
+ value = Component(props, context);
709
} else {
613
- value = fn(props, context);
710
+ value = Component(props, context);
711
}
712
// React DevTools reads this flag.
713
workInProgress.effectTag |= PerformedWork;
718
typeof value.render === 'function' &&
719
value.$$typeof === undefined
720
) {
624
- const Component = workInProgress.type;
625
-
721
// Proceed under the assumption that this is a class instance
722
workInProgress.tag = ClassComponent;
723
724
// Push context providers early to prevent context stack mismatches.
725
// During mounting we don't know the child context yet as the instance doesn't exist.
726
// We will invalidate the child context in finishClassComponent() right after rendering.
632
- const hasContext = pushLegacyContextProvider(workInProgress);
727
+ let hasContext = false;
728
+ if (isLegacyContextProvider(Component)) {
729
+ hasContext = true;
730
+ pushLegacyContextProvider(workInProgress);
731
+ } else {
732
+ hasContext = false;
733
+ }
734
735
workInProgress.memoizedState =
736
value.state !== null && value.state !== undefined ? value.state : null;
739
if (typeof getDerivedStateFromProps === 'function') {
740
applyDerivedStateFromProps(
741
workInProgress,
742
+ Component,
743
getDerivedStateFromProps,
744
props,
745
);
746
}
747
748
adoptClassInstance(workInProgress, value);
647
- mountClassInstance(workInProgress, renderExpirationTime);
749
+ mountClassInstance(workInProgress, Component, props, renderExpirationTime);
750
return finishClassComponent(
751
current,
752
workInProgress,
753
+ Component,
754
true,
755
hasContext,
756
renderExpirationTime,
759
// Proceed under the assumption that this is a functional component
760
workInProgress.tag = FunctionalComponent;
761
if (__DEV__) {
659
- const Component = workInProgress.type;
660
-
762
if (Component) {
763
warningWithoutStack(
764
!Component.childContextTypes,
789
}
790
}
791
691
- if (typeof fn.getDerivedStateFromProps === 'function') {
692
- const componentName = getComponentName(fn) || 'Unknown';
792
+ if (typeof Component.getDerivedStateFromProps === 'function') {
793
+ const componentName = getComponentName(Component) || 'Unknown';
794
795
if (!didWarnAboutGetDerivedStateOnFunctionalComponent[componentName]) {
796
warningWithoutStack(
1095
case HostComponent:
1096
pushHostContext(workInProgress);
1097
break;
997
- case ClassComponent:
998
- pushLegacyContextProvider(workInProgress);
1098
+ case ClassComponent: {
1099
+ const Component = workInProgress.type;
1100
+ if (isLegacyContextProvider(Component)) {
1101
+ pushLegacyContextProvider(workInProgress);
1102
+ }
1103
+ break;
1104
+ }
1105
+ case ClassComponentLazy: {
1106
+ const thenable = workInProgress.type;
1107
+ const Component = getResultFromResolvedThenable(thenable);
1108
+ if (isLegacyContextProvider(Component)) {
1109
+ pushLegacyContextProvider(workInProgress);
1110
+ }
1111
break;
1112
+ }
1113
case HostPortal:
1114
pushHostContainer(
1115
workInProgress,
1138
workInProgress.expirationTime = NoWork;
1139
1140
switch (workInProgress.tag) {
1028
- case IndeterminateComponent:
1141
+ case IndeterminateComponent: {
1142
+ const Component = workInProgress.type;
1143
return mountIndeterminateComponent(
1144
current,
1145
workInProgress,
1146
+ Component,
1147
renderExpirationTime,
1148
);
1034
- case FunctionalComponent:
1149
+ }
1150
+ case FunctionalComponent: {
1151
+ const Component = workInProgress.type;
1152
+ const unresolvedProps = workInProgress.pendingProps;
1153
return updateFunctionalComponent(
1154
current,
1155
workInProgress,
1156
+ Component,
1157
+ unresolvedProps,
1158
+ renderExpirationTime,
1159
+ );
1160
+ }
1161
+ case FunctionalComponentLazy: {
1162
+ const thenable = workInProgress.type;
1163
+ const Component = getResultFromResolvedThenable(thenable);
1164
+ const unresolvedProps = workInProgress.pendingProps;
1165
+ const child = updateFunctionalComponent(
1166
+ current,
1167
+ workInProgress,
1168
+ Component,
1169
+ resolveDefaultProps(Component, unresolvedProps),
1170
renderExpirationTime,
1171
);
1040
- case ClassComponent:
1172
+ workInProgress.memoizedProps = unresolvedProps;
1173
+ return child;
1174
+ }
1175
+ case ClassComponent: {
1176
+ const Component = workInProgress.type;
1177
+ const unresolvedProps = workInProgress.pendingProps;
1178
return updateClassComponent(
1179
current,
1180
workInProgress,
1181
+ Component,
1182
+ unresolvedProps,
1183
renderExpirationTime,
1184
);
1185
+ }
1186
+ case ClassComponentLazy: {
1187
+ const thenable = workInProgress.type;
1188
+ const Component = getResultFromResolvedThenable(thenable);
1189
+ const unresolvedProps = workInProgress.pendingProps;
1190
+ const child = updateClassComponent(
1191
+ current,
1192
+ workInProgress,
1193
+ Component,
1194
+ resolveDefaultProps(Component, unresolvedProps),
1195
+ renderExpirationTime,
1196
+ );
1197
+ workInProgress.memoizedProps = unresolvedProps;
1198
+ return child;
1199
+ }
1200
case HostRoot:
1201
return updateHostRoot(current, workInProgress, renderExpirationTime);
1202
case HostComponent:
1215
workInProgress,
1216
renderExpirationTime,
1217
);
1064
- case ForwardRef:
1065
- return updateForwardRef(current, workInProgress, renderExpirationTime);
1218
+ case ForwardRef: {
1219
+ const type = workInProgress.type;
1220
+ return updateForwardRef(
1221
+ current,
1222
+ workInProgress,
1223
+ type,
1224
+ workInProgress.pendingProps,
1225
+ renderExpirationTime,
1226
+ );
1227
+ }
1228
+ case ForwardRefLazy:
1229
+ const thenable = workInProgress.type;
1230
+ const Component = getResultFromResolvedThenable(thenable);
1231
+ const unresolvedProps = workInProgress.pendingProps;
1232
+ const child = updateForwardRef(
1233
+ current,
1234
+ workInProgress,
1235
+ Component,
1236
+ resolveDefaultProps(Component, unresolvedProps),
1237
+ renderExpirationTime,
1238
+ );
1239
+ workInProgress.memoizedProps = unresolvedProps;
1240
+ return child;
1241
case Fragment:
1242
return updateFragment(current, workInProgress, renderExpirationTime);
1243
case Mode: