Skip to content

Commit 6103fc0

Browse files
committed
Resolve defaultProps for lazy types
1 parent 4f11c94 commit 6103fc0

File tree

2 files changed

+138
-12
lines changed

2 files changed

+138
-12
lines changed

packages/react-reconciler/src/ReactFiberBeginWork.js

Lines changed: 107 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,34 @@ function updateForwardRef(
191191
return workInProgress.child;
192192
}
193193

194+
function updateForwardRefLazy(
195+
current: Fiber | null,
196+
workInProgress: Fiber,
197+
Component: any,
198+
renderExpirationTime: ExpirationTime,
199+
) {
200+
const props = workInProgress.pendingProps;
201+
const resolvedProps = resolveDefaultProps(Component, props);
202+
if (resolvedProps !== null) {
203+
workInProgress.pendingProps = resolvedProps;
204+
const child = updateForwardRef(
205+
current,
206+
workInProgress,
207+
Component,
208+
renderExpirationTime,
209+
);
210+
workInProgress.pendingProps = workInProgress.memoizedProps = props;
211+
return child;
212+
} else {
213+
return updateForwardRef(
214+
current,
215+
workInProgress,
216+
Component,
217+
renderExpirationTime,
218+
);
219+
}
220+
}
221+
194222
function updateFragment(
195223
current: Fiber | null,
196224
workInProgress: Fiber,
@@ -287,6 +315,34 @@ function updateFunctionalComponent(
287315
return workInProgress.child;
288316
}
289317

318+
function updateFunctionalComponentLazy(
319+
current,
320+
workInProgress,
321+
Component,
322+
renderExpirationTime,
323+
) {
324+
const props = workInProgress.pendingProps;
325+
const resolvedProps = resolveDefaultProps(Component, props);
326+
if (resolvedProps !== null) {
327+
workInProgress.pendingProps = resolvedProps;
328+
const child = updateFunctionalComponent(
329+
current,
330+
workInProgress,
331+
Component,
332+
renderExpirationTime,
333+
);
334+
workInProgress.pendingProps = workInProgress.memoizedProps = props;
335+
return child;
336+
} else {
337+
return updateFunctionalComponent(
338+
current,
339+
workInProgress,
340+
Component,
341+
renderExpirationTime,
342+
);
343+
}
344+
}
345+
290346
function updateClassComponent(
291347
current: Fiber | null,
292348
workInProgress: Fiber,
@@ -436,6 +492,34 @@ function finishClassComponent(
436492
return workInProgress.child;
437493
}
438494

495+
function updateClassComponentLazy(
496+
current,
497+
workInProgress,
498+
Component,
499+
renderExpirationTime,
500+
) {
501+
const props = workInProgress.pendingProps;
502+
const resolvedProps = resolveDefaultProps(Component, props);
503+
if (resolvedProps !== null) {
504+
workInProgress.pendingProps = resolvedProps;
505+
const child = updateClassComponent(
506+
current,
507+
workInProgress,
508+
Component,
509+
renderExpirationTime,
510+
);
511+
workInProgress.pendingProps = workInProgress.memoizedProps = props;
512+
return child;
513+
} else {
514+
return updateClassComponent(
515+
current,
516+
workInProgress,
517+
Component,
518+
renderExpirationTime,
519+
);
520+
}
521+
}
522+
439523
function pushHostRootContext(workInProgress) {
440524
const root = (workInProgress.stateNode: FiberRoot);
441525
if (root.pendingContext) {
@@ -585,6 +669,21 @@ function updateHostText(current, workInProgress) {
585669
return null;
586670
}
587671

672+
function resolveDefaultProps(Component, baseProps) {
673+
if (Component && Component.defaultProps) {
674+
// Resolve default props. Taken from ReactElement
675+
const props = Object.assign({}, baseProps);
676+
const defaultProps = Component.defaultProps;
677+
for (let propName in defaultProps) {
678+
if (props[propName] === undefined) {
679+
props[propName] = defaultProps[propName];
680+
}
681+
}
682+
return props;
683+
}
684+
return null;
685+
}
686+
588687
function mountIndeterminateComponent(
589688
current,
590689
workInProgress,
@@ -597,6 +696,7 @@ function mountIndeterminateComponent(
597696
'likely caused by a bug in React. Please file an issue.',
598697
);
599698

699+
const props = workInProgress.pendingProps;
600700
if (
601701
Component !== null &&
602702
Component !== undefined &&
@@ -606,32 +706,28 @@ function mountIndeterminateComponent(
606706
if (typeof Component === 'function') {
607707
if (shouldConstruct(Component)) {
608708
workInProgress.tag = ClassComponentLazy;
609-
return updateClassComponent(
709+
return updateClassComponentLazy(
610710
current,
611711
workInProgress,
612712
Component,
613713
renderExpirationTime,
614714
);
615715
} else {
616-
const child = mountIndeterminateComponent(
716+
workInProgress.tag = FunctionalComponentLazy;
717+
return updateFunctionalComponentLazy(
617718
current,
618719
workInProgress,
619720
Component,
620721
renderExpirationTime,
621722
);
622-
workInProgress.tag =
623-
workInProgress.tag === FunctionalComponent
624-
? FunctionalComponentLazy
625-
: ClassComponentLazy;
626-
return child;
627723
}
628724
} else if (
629725
Component !== undefined &&
630726
Component !== null &&
631727
Component.$$typeof
632728
) {
633729
workInProgress.tag = ForwardRefLazy;
634-
return updateForwardRef(
730+
return updateForwardRefLazy(
635731
current,
636732
workInProgress,
637733
Component,
@@ -640,7 +736,6 @@ function mountIndeterminateComponent(
640736
}
641737
}
642738

643-
const props = workInProgress.pendingProps;
644739
const unmaskedContext = getUnmaskedContext(workInProgress);
645740
const context = getMaskedContext(workInProgress, unmaskedContext);
646741

@@ -1112,7 +1207,7 @@ function beginWork(
11121207
case FunctionalComponentLazy: {
11131208
const thenable = workInProgress.type;
11141209
const Component = (thenable._reactResult: any);
1115-
return updateFunctionalComponent(
1210+
return updateFunctionalComponentLazy(
11161211
current,
11171212
workInProgress,
11181213
Component,
@@ -1131,7 +1226,7 @@ function beginWork(
11311226
case ClassComponentLazy: {
11321227
const thenable = workInProgress.type;
11331228
const Component = (thenable._reactResult: any);
1134-
return updateClassComponent(
1229+
return updateClassComponentLazy(
11351230
current,
11361231
workInProgress,
11371232
Component,
@@ -1168,7 +1263,7 @@ function beginWork(
11681263
case ForwardRefLazy:
11691264
const thenable = workInProgress.type;
11701265
const Component = (thenable._reactResult: any);
1171-
return updateForwardRef(
1266+
return updateForwardRefLazy(
11721267
current,
11731268
workInProgress,
11741269
Component,

packages/react-reconciler/src/__tests__/ReactSuspense-test.internal.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1472,6 +1472,37 @@ describe('ReactSuspense', () => {
14721472
expect(ReactNoop.flush()).toEqual(['Hi again']);
14731473
expect(ReactNoop.getChildren()).toEqual([span('Hi again')]);
14741474
});
1475+
1476+
it('resolves defaultProps, on mount and update', async () => {
1477+
function T(props) {
1478+
return <Text {...props} />;
1479+
}
1480+
T.defaultProps = {text: 'Hi'};
1481+
const LazyText = Promise.resolve(T);
1482+
1483+
ReactNoop.render(
1484+
<Placeholder fallback={<Text text="Loading..." />}>
1485+
<LazyText />
1486+
</Placeholder>,
1487+
);
1488+
expect(ReactNoop.flush()).toEqual(['Loading...']);
1489+
expect(ReactNoop.getChildren()).toEqual([]);
1490+
1491+
await LazyText;
1492+
1493+
expect(ReactNoop.flush()).toEqual(['Hi']);
1494+
expect(ReactNoop.getChildren()).toEqual([span('Hi')]);
1495+
1496+
T.defaultProps = {text: 'Hi again'};
1497+
1498+
ReactNoop.render(
1499+
<Placeholder fallback={<Text text="Loading..." />}>
1500+
<LazyText text="Hi again" />
1501+
</Placeholder>,
1502+
);
1503+
expect(ReactNoop.flush()).toEqual(['Hi again']);
1504+
expect(ReactNoop.getChildren()).toEqual([span('Hi again')]);
1505+
});
14751506
});
14761507

14771508
it('does not call lifecycles of a suspended component', async () => {

0 commit comments

Comments
 (0)