Skip to content

Commit e8d3c6b

Browse files
committed
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 23b32d3 commit e8d3c6b

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
@@ -42,7 +42,6 @@ import {
4242
import {NoFlags, Placement, StaticMask} from './ReactFiberFlags';
4343
import {ConcurrentRoot} from './ReactRootTags';
4444
import {
45-
IndeterminateComponent,
4645
ClassComponent,
4746
HostRoot,
4847
HostComponent,
@@ -248,19 +247,10 @@ export function isSimpleFunctionComponent(type: any): boolean {
248247
);
249248
}
250249

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

266256
// This is used to create an alternate fiber to do work on.
@@ -351,7 +341,6 @@ export function createWorkInProgress(current: Fiber, pendingProps: any): Fiber {
351341
workInProgress._debugInfo = current._debugInfo;
352342
workInProgress._debugNeedsRemount = current._debugNeedsRemount;
353343
switch (workInProgress.tag) {
354-
case IndeterminateComponent:
355344
case FunctionComponent:
356345
case SimpleMemoComponent:
357346
workInProgress.type = resolveFunctionForHotReloading(current.type);
@@ -492,7 +481,7 @@ export function createFiberFromTypeAndProps(
492481
mode: TypeOfMode,
493482
lanes: Lanes,
494483
): Fiber {
495-
let fiberTag = IndeterminateComponent;
484+
let fiberTag = FunctionComponent;
496485
// The resolved type is set if we know what the final type will be. I.e. it's not lazy.
497486
let resolvedType = type;
498487
if (typeof type === 'function') {

0 commit comments

Comments
 (0)