Skip to content

Commit 4d24105

Browse files
gnoffAndyPengc12
authored andcommitted
Reland facebook#28672: Remove IndeterminateComponent (facebook#28681)
This PR relands facebook#28672 on top of the flag removal and the test demonstrating a breakage in Suspense for legacy mode. React has deprecated module pattern Function Components for many years at this point. Supporting this pattern required React to have a concept of an indeterminate component so that when a component first renders it can turn into either a ClassComponent or a FunctionComponent depending on what it returns. While this feature was deprecated and put behind a flag it is still in stable. This change remvoes the flag, removes the warnings, and removes the concept of IndeterminateComponent from the React codebase. While removing IndeterminateComponent type Seb and I discovered that we needed a concept of IncompleteFunctionComponent to support Suspense in legacy mode. This new work tag is only needed as long as legacy mode is around and ideally any code that considers this tag will be excludable from OSS builds once we land extra gates using `disableLegacyMode` flag.
1 parent 803ac73 commit 4d24105

15 files changed

+149
-257
lines changed

packages/react-devtools-shared/src/backend/renderer.js

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,8 @@ export function getInternalReactConstants(version: string): {
225225
HostSingleton: 27, // Same as above
226226
HostText: 6,
227227
IncompleteClassComponent: 17,
228-
IndeterminateComponent: 2,
228+
IncompleteFunctionComponent: 28,
229+
IndeterminateComponent: 2, // removed in 19.0.0
229230
LazyComponent: 16,
230231
LegacyHiddenComponent: 23,
231232
MemoComponent: 14,
@@ -259,6 +260,7 @@ export function getInternalReactConstants(version: string): {
259260
HostSingleton: -1, // Doesn't exist yet
260261
HostText: 6,
261262
IncompleteClassComponent: 17,
263+
IncompleteFunctionComponent: -1, // Doesn't exist yet
262264
IndeterminateComponent: 2,
263265
LazyComponent: 16,
264266
LegacyHiddenComponent: 24,
@@ -292,6 +294,7 @@ export function getInternalReactConstants(version: string): {
292294
HostSingleton: -1, // Doesn't exist yet
293295
HostText: 6,
294296
IncompleteClassComponent: 17,
297+
IncompleteFunctionComponent: -1, // Doesn't exist yet
295298
IndeterminateComponent: 2,
296299
LazyComponent: 16,
297300
LegacyHiddenComponent: -1,
@@ -325,6 +328,7 @@ export function getInternalReactConstants(version: string): {
325328
HostSingleton: -1, // Doesn't exist yet
326329
HostText: 8,
327330
IncompleteClassComponent: -1, // Doesn't exist yet
331+
IncompleteFunctionComponent: -1, // Doesn't exist yet
328332
IndeterminateComponent: 4,
329333
LazyComponent: -1, // Doesn't exist yet
330334
LegacyHiddenComponent: -1,
@@ -358,6 +362,7 @@ export function getInternalReactConstants(version: string): {
358362
HostSingleton: -1, // Doesn't exist yet
359363
HostText: 6,
360364
IncompleteClassComponent: -1, // Doesn't exist yet
365+
IncompleteFunctionComponent: -1, // Doesn't exist yet
361366
IndeterminateComponent: 0,
362367
LazyComponent: -1, // Doesn't exist yet
363368
LegacyHiddenComponent: -1,
@@ -391,6 +396,7 @@ export function getInternalReactConstants(version: string): {
391396
CacheComponent,
392397
ClassComponent,
393398
IncompleteClassComponent,
399+
IncompleteFunctionComponent,
394400
FunctionComponent,
395401
IndeterminateComponent,
396402
ForwardRef,
@@ -459,6 +465,7 @@ export function getInternalReactConstants(version: string): {
459465
return 'Cache';
460466
case ClassComponent:
461467
case IncompleteClassComponent:
468+
case IncompleteFunctionComponent:
462469
case FunctionComponent:
463470
case IndeterminateComponent:
464471
return getDisplayName(resolvedType);
@@ -624,6 +631,7 @@ export function attach(
624631
HostComponent,
625632
HostText,
626633
IncompleteClassComponent,
634+
IncompleteFunctionComponent,
627635
IndeterminateComponent,
628636
LegacyHiddenComponent,
629637
MemoComponent,
@@ -1061,6 +1069,7 @@ export function attach(
10611069
case ClassComponent:
10621070
case IncompleteClassComponent:
10631071
return ElementTypeClass;
1072+
case IncompleteFunctionComponent:
10641073
case FunctionComponent:
10651074
case IndeterminateComponent:
10661075
return ElementTypeFunction;
@@ -3059,6 +3068,7 @@ export function attach(
30593068
switch (tag) {
30603069
case ClassComponent:
30613070
case IncompleteClassComponent:
3071+
case IncompleteFunctionComponent:
30623072
case IndeterminateComponent:
30633073
case FunctionComponent:
30643074
global.$type = type;
@@ -3193,6 +3203,7 @@ export function attach(
31933203
tag === ClassComponent ||
31943204
tag === FunctionComponent ||
31953205
tag === IncompleteClassComponent ||
3206+
tag === IncompleteFunctionComponent ||
31963207
tag === IndeterminateComponent ||
31973208
tag === MemoComponent ||
31983209
tag === ForwardRef ||
@@ -3540,6 +3551,7 @@ export function attach(
35403551
case IndeterminateComponent:
35413552
global.$r = stateNode;
35423553
break;
3554+
case IncompleteFunctionComponent:
35433555
case FunctionComponent:
35443556
global.$r = {
35453557
hooks,

packages/react-devtools-shared/src/backend/types.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ export type WorkTagMap = {
5858
HostSingleton: WorkTag,
5959
HostText: WorkTag,
6060
IncompleteClassComponent: WorkTag,
61+
IncompleteFunctionComponent: WorkTag,
6162
IndeterminateComponent: WorkTag,
6263
LazyComponent: WorkTag,
6364
LegacyHiddenComponent: WorkTag,

packages/react-dom/src/__tests__/ReactCompositeComponent-test.js

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -223,23 +223,16 @@ describe('ReactCompositeComponent', () => {
223223
const el = document.createElement('div');
224224
const root = ReactDOMClient.createRoot(el);
225225
await expect(async () => {
226-
await expect(async () => {
227-
await act(() => {
228-
root.render(<Child test="test" />);
229-
});
230-
}).rejects.toThrow(
231-
'Objects are not valid as a React child (found: object with keys {render}).',
232-
);
233-
}).toErrorDev(
234-
'Warning: The <Child /> component appears to be a function component that returns a class instance. ' +
235-
'Change Child to a class that extends React.Component instead. ' +
236-
"If you can't use a class try assigning the prototype on the function as a workaround. " +
237-
'`Child.prototype = React.Component.prototype`. ' +
238-
"Don't use an arrow function since it cannot be called with `new` by React.",
226+
await act(() => {
227+
root.render(<Child test="test" />);
228+
});
229+
}).rejects.toThrow(
230+
'Objects are not valid as a React child (found: object with keys {render}).',
239231
);
240232

241233
expect(el.textContent).toBe('');
242234
});
235+
243236
it('should use default values for undefined props', async () => {
244237
class Component extends React.Component {
245238
static defaultProps = {prop: 'testKey'};

packages/react-reconciler/src/ReactFiber.js

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ import {
4141
import {NoFlags, Placement, StaticMask} from './ReactFiberFlags';
4242
import {ConcurrentRoot} from './ReactRootTags';
4343
import {
44-
IndeterminateComponent,
4544
ClassComponent,
4645
HostRoot,
4746
HostComponent,
@@ -245,19 +244,10 @@ export function isSimpleFunctionComponent(type: any): boolean {
245244
);
246245
}
247246

248-
export function resolveLazyComponentTag(Component: Function): WorkTag {
249-
if (typeof Component === 'function') {
250-
return shouldConstruct(Component) ? ClassComponent : FunctionComponent;
251-
} else if (Component !== undefined && Component !== null) {
252-
const $$typeof = Component.$$typeof;
253-
if ($$typeof === REACT_FORWARD_REF_TYPE) {
254-
return ForwardRef;
255-
}
256-
if ($$typeof === REACT_MEMO_TYPE) {
257-
return MemoComponent;
258-
}
259-
}
260-
return IndeterminateComponent;
247+
export function isFunctionClassComponent(
248+
type: (...args: Array<any>) => mixed,
249+
): boolean {
250+
return shouldConstruct(type);
261251
}
262252

263253
// This is used to create an alternate fiber to do work on.
@@ -348,7 +338,6 @@ export function createWorkInProgress(current: Fiber, pendingProps: any): Fiber {
348338
workInProgress._debugInfo = current._debugInfo;
349339
workInProgress._debugNeedsRemount = current._debugNeedsRemount;
350340
switch (workInProgress.tag) {
351-
case IndeterminateComponent:
352341
case FunctionComponent:
353342
case SimpleMemoComponent:
354343
workInProgress.type = resolveFunctionForHotReloading(current.type);
@@ -489,7 +478,7 @@ export function createFiberFromTypeAndProps(
489478
mode: TypeOfMode,
490479
lanes: Lanes,
491480
): Fiber {
492-
let fiberTag = IndeterminateComponent;
481+
let fiberTag = FunctionComponent;
493482
// The resolved type is set if we know what the final type will be. I.e. it's not lazy.
494483
let resolvedType = type;
495484
if (typeof type === 'function') {

0 commit comments

Comments
 (0)