Replace unstable_AsyncComponent with unstable_AsyncMode (#12117)
* Replace unstable_AsyncComponent with Unstable_AsyncMode Mirrors the StrictMode API and uses the new Mode type of work. * internalContextTag -> mode Change this now that we have a better name * Unstable_ -> unstable_
Andrew Clark committed
Jan 29, 2018 at 19:11 UTC
9ea55516e674c2de63b9f7829e3c459f3cb3cf78
19 files changed
+131
-145
packages/react-dom/src/__tests__/ReactDOMFiberAsync-test.internal.js
+19
-20
@@ -14,7 +14,7 @@ let ReactFeatureFlags = require('shared/ReactFeatureFlags');
14
15
let ReactDOM;
16
17
-const AsyncComponent = React.unstable_AsyncComponent;
17
+const AsyncMode = React.unstable_AsyncMode;
18
19
describe('ReactDOMFiberAsync', () => {
20
let container;
@@ -40,23 +40,22 @@ describe('ReactDOMFiberAsync', () => {
40
jest.resetModules();
41
ReactFeatureFlags = require('shared/ReactFeatureFlags');
42
container = document.createElement('div');
43
- ReactFeatureFlags.enableAsyncSubtreeAPI = false;
43
ReactDOM = require('react-dom');
44
});
45
46
it('renders synchronously', () => {
47
ReactDOM.render(
49
- <AsyncComponent>
48
+ <AsyncMode>
49
<div>Hi</div>
51
- </AsyncComponent>,
50
+ </AsyncMode>,
51
container,
52
);
53
expect(container.textContent).toEqual('Hi');
54
55
ReactDOM.render(
57
- <AsyncComponent>
56
+ <AsyncMode>
57
<div>Bye</div>
59
- </AsyncComponent>,
58
+ </AsyncMode>,
59
container,
60
);
61
expect(container.textContent).toEqual('Bye');
@@ -68,7 +67,6 @@ describe('ReactDOMFiberAsync', () => {
67
jest.resetModules();
68
ReactFeatureFlags = require('shared/ReactFeatureFlags');
69
container = document.createElement('div');
71
- ReactFeatureFlags.enableAsyncSubtreeAPI = true;
70
ReactFeatureFlags.enableCreateRoot = true;
71
ReactDOM = require('react-dom');
72
});
@@ -108,9 +106,9 @@ describe('ReactDOMFiberAsync', () => {
106
expect(container.textContent).toEqual('1');
107
});
108
111
- it('AsyncComponent creates an async subtree', () => {
109
+ it('AsyncMode creates an async subtree', () => {
110
let instance;
113
- class Component extends React.unstable_AsyncComponent {
111
+ class Component extends React.Component {
112
state = {step: 0};
113
render() {
114
instance = this;
@@ -119,9 +117,9 @@ describe('ReactDOMFiberAsync', () => {
117
}
118
119
ReactDOM.render(
122
- <div>
120
+ <AsyncMode>
121
<Component />
124
- </div>,
122
+ </AsyncMode>,
123
container,
124
);
125
jest.runAllTimers();
@@ -133,12 +131,6 @@ describe('ReactDOMFiberAsync', () => {
131
});
132
133
it('updates inside an async subtree are async by default', () => {
136
- class Component extends React.unstable_AsyncComponent {
137
- render() {
138
- return <Child />;
139
- }
140
- }
141
-
134
let instance;
135
class Child extends React.Component {
136
state = {step: 0};
@@ -150,7 +142,9 @@ describe('ReactDOMFiberAsync', () => {
142
143
ReactDOM.render(
144
<div>
153
- <Component />
145
+ <AsyncMode>
146
+ <Child />
147
+ </AsyncMode>
148
</div>,
149
container,
150
);
@@ -264,7 +258,7 @@ describe('ReactDOMFiberAsync', () => {
258
let ops = [];
259
let instance;
260
267
- class Component extends React.unstable_AsyncComponent {
261
+ class Component extends React.Component {
262
state = {text: ''};
263
push(val) {
264
this.setState(state => ({text: state.text + val}));
@@ -278,7 +272,12 @@ describe('ReactDOMFiberAsync', () => {
272
}
273
}
274
281
- ReactDOM.render(<Component />, container);
275
+ ReactDOM.render(
276
+ <AsyncMode>
277
+ <Component />
278
+ </AsyncMode>,
279
+ container,
280
+ );
281
jest.runAllTimers();
282
283
// Updates are async by default
packages/react-dom/src/__tests__/ReactDOMRoot-test.internal.js
+6
-7
@@ -12,7 +12,7 @@
12
let React = require('react');
13
let ReactDOM = require('react-dom');
14
let ReactDOMServer = require('react-dom/server');
15
-let AsyncComponent = React.unstable_AsyncComponent;
15
+let AsyncMode = React.unstable_AsyncMode;
16
17
describe('ReactDOMRoot', () => {
18
let container;
@@ -70,7 +70,7 @@ describe('ReactDOMRoot', () => {
70
React = require('react');
71
ReactDOM = require('react-dom');
72
ReactDOMServer = require('react-dom/server');
73
- AsyncComponent = React.unstable_AsyncComponent;
73
+ AsyncMode = React.unstable_AsyncMode;
74
});
75
76
it('renders children', () => {
@@ -92,7 +92,7 @@ describe('ReactDOMRoot', () => {
92
93
it('`root.render` returns a thenable work object', () => {
94
const root = ReactDOM.createRoot(container);
95
- const work = root.render(<AsyncComponent>Hi</AsyncComponent>);
95
+ const work = root.render(<AsyncMode>Hi</AsyncMode>);
96
let ops = [];
97
work.then(() => {
98
ops.push('inside callback: ' + container.textContent);
@@ -110,7 +110,7 @@ describe('ReactDOMRoot', () => {
110
111
it('resolves `work.then` callback synchronously if the work already committed', () => {
112
const root = ReactDOM.createRoot(container);
113
- const work = root.render(<AsyncComponent>Hi</AsyncComponent>);
113
+ const work = root.render(<AsyncMode>Hi</AsyncMode>);
114
flush();
115
let ops = [];
116
work.then(() => {
@@ -209,10 +209,9 @@ describe('ReactDOMRoot', () => {
209
});
210
211
it('can wait for a batch to finish', () => {
212
- const Async = React.unstable_AsyncComponent;
212
const root = ReactDOM.createRoot(container);
213
const batch = root.createBatch();
215
- batch.render(<Async>Foo</Async>);
214
+ batch.render(<AsyncMode>Foo</AsyncMode>);
215
216
flush();
217
@@ -252,7 +251,7 @@ describe('ReactDOMRoot', () => {
251
252
it('can commit an empty batch', () => {
253
const root = ReactDOM.createRoot(container);
255
- root.render(<AsyncComponent>1</AsyncComponent>);
254
+ root.render(<AsyncMode>1</AsyncMode>);
255
256
expire(2000);
257
// This batch has a later expiration time than the earlier update.
packages/react-reconciler/src/ReactChildFiber.js
+12
-12
@@ -318,7 +318,7 @@ function ChildReconciler(shouldTrackSideEffects) {
318
// Insert
319
const created = createFiberFromText(
320
textContent,
321
- returnFiber.internalContextTag,
321
+ returnFiber.mode,
322
expirationTime,
323
);
324
created.return = returnFiber;
@@ -351,7 +351,7 @@ function ChildReconciler(shouldTrackSideEffects) {
351
// Insert
352
const created = createFiberFromElement(
353
element,
354
- returnFiber.internalContextTag,
354
+ returnFiber.mode,
355
expirationTime,
356
);
357
created.ref = coerceRef(current, element);
@@ -375,7 +375,7 @@ function ChildReconciler(shouldTrackSideEffects) {
375
// Insert
376
const created = createFiberFromPortal(
377
portal,
378
- returnFiber.internalContextTag,
378
+ returnFiber.mode,
379
expirationTime,
380
);
381
created.return = returnFiber;
@@ -399,7 +399,7 @@ function ChildReconciler(shouldTrackSideEffects) {
399
// Insert
400
const created = createFiberFromFragment(
401
fragment,
402
- returnFiber.internalContextTag,
402
+ returnFiber.mode,
403
expirationTime,
404
key,
405
);
@@ -424,7 +424,7 @@ function ChildReconciler(shouldTrackSideEffects) {
424
// node.
425
const created = createFiberFromText(
426
'' + newChild,
427
- returnFiber.internalContextTag,
427
+ returnFiber.mode,
428
expirationTime,
429
);
430
created.return = returnFiber;
@@ -436,7 +436,7 @@ function ChildReconciler(shouldTrackSideEffects) {
436
case REACT_ELEMENT_TYPE: {
437
const created = createFiberFromElement(
438
newChild,
439
- returnFiber.internalContextTag,
439
+ returnFiber.mode,
440
expirationTime,
441
);
442
created.ref = coerceRef(null, newChild);
@@ -446,7 +446,7 @@ function ChildReconciler(shouldTrackSideEffects) {
446
case REACT_PORTAL_TYPE: {
447
const created = createFiberFromPortal(
448
newChild,
449
- returnFiber.internalContextTag,
449
+ returnFiber.mode,
450
expirationTime,
451
);
452
created.return = returnFiber;
@@ -457,7 +457,7 @@ function ChildReconciler(shouldTrackSideEffects) {
457
if (isArray(newChild) || getIteratorFn(newChild)) {
458
const created = createFiberFromFragment(
459
newChild,
460
- returnFiber.internalContextTag,
460
+ returnFiber.mode,
461
expirationTime,
462
null,
463
);
@@ -1045,7 +1045,7 @@ function ChildReconciler(shouldTrackSideEffects) {
1045
deleteRemainingChildren(returnFiber, currentFirstChild);
1046
const created = createFiberFromText(
1047
textContent,
1048
- returnFiber.internalContextTag,
1048
+ returnFiber.mode,
1049
expirationTime,
1050
);
1051
created.return = returnFiber;
@@ -1097,7 +1097,7 @@ function ChildReconciler(shouldTrackSideEffects) {
1097
if (element.type === REACT_FRAGMENT_TYPE) {
1098
const created = createFiberFromFragment(
1099
element.props.children,
1100
- returnFiber.internalContextTag,
1100
+ returnFiber.mode,
1101
expirationTime,
1102
element.key,
1103
);
@@ -1106,7 +1106,7 @@ function ChildReconciler(shouldTrackSideEffects) {
1106
} else {
1107
const created = createFiberFromElement(
1108
element,
1109
- returnFiber.internalContextTag,
1109
+ returnFiber.mode,
1110
expirationTime,
1111
);
1112
created.ref = coerceRef(currentFirstChild, element);
@@ -1152,7 +1152,7 @@ function ChildReconciler(shouldTrackSideEffects) {
1152
1153
const created = createFiberFromPortal(
1154
portal,
1155
- returnFiber.internalContextTag,
1155
+ returnFiber.mode,
1156
expirationTime,
1157
);
1158
created.return = returnFiber;
packages/react-reconciler/src/ReactFiber.js
+27
-31
@@ -9,7 +9,7 @@
9
import type {ReactElement, Source} from 'shared/ReactElementType';
10
import type {ReactPortal} from 'shared/ReactTypes';
11
import type {TypeOfWork} from 'shared/ReactTypeOfWork';
12
-import type {TypeOfInternalContext} from './ReactTypeOfInternalContext';
12
+import type {TypeOfMode} from './ReactTypeOfMode';
13
import type {TypeOfSideEffect} from 'shared/ReactTypeOfSideEffect';
14
import type {ExpirationTime} from './ReactFiberExpirationTime';
15
import type {UpdateQueue} from './ReactFiberUpdateQueue';
@@ -33,11 +33,7 @@ import {
33
import getComponentName from 'shared/getComponentName';
34
35
import {NoWork} from './ReactFiberExpirationTime';
36
-import {
37
- NoContext,
38
- AsyncUpdates,
39
- StrictMode,
40
-} from './ReactTypeOfInternalContext';
36
+import {NoContext, AsyncMode, StrictMode} from './ReactTypeOfMode';
37
import {
38
REACT_FRAGMENT_TYPE,
39
REACT_RETURN_TYPE,
@@ -45,6 +41,7 @@ import {
41
REACT_STRICT_MODE_TYPE,
42
REACT_PROVIDER_TYPE,
43
REACT_CONTEXT_TYPE,
44
+ REACT_ASYNC_MODE_TYPE,
45
} from 'shared/ReactSymbols';
46
47
let hasBadMapPolyfill;
@@ -123,12 +120,12 @@ export type Fiber = {|
120
memoizedState: any,
121
122
// Bitfield that describes properties about the fiber and its subtree. E.g.
126
- // the AsyncUpdates flag indicates whether the subtree should be async-by-
127
- // default. When a fiber is created, it inherits the internalContextTag of its
123
+ // the AsyncMode flag indicates whether the subtree should be async-by-
124
+ // default. When a fiber is created, it inherits the mode of its
125
// parent. Additional flags can be set at creation time, but after than the
126
// value should remain unchanged throughout the fiber's lifetime, particularly
127
// before its child fibers are created.
131
- internalContextTag: TypeOfInternalContext,
128
+ mode: TypeOfMode,
129
130
// Effect
131
effectTag: TypeOfSideEffect,
@@ -171,7 +168,7 @@ function FiberNode(
168
tag: TypeOfWork,
169
pendingProps: mixed,
170
key: null | string,
174
- internalContextTag: TypeOfInternalContext,
171
+ mode: TypeOfMode,
172
) {
173
// Instance
174
this.tag = tag;
@@ -192,7 +189,7 @@ function FiberNode(
189
this.updateQueue = null;
190
this.memoizedState = null;
191
195
- this.internalContextTag = internalContextTag;
192
+ this.mode = mode;
193
194
// Effects
195
this.effectTag = NoEffect;
@@ -233,10 +230,10 @@ const createFiber = function(
230
tag: TypeOfWork,
231
pendingProps: mixed,
232
key: null | string,
236
- internalContextTag: TypeOfInternalContext,
233
+ mode: TypeOfMode,
234
): Fiber {
235
// $FlowFixMe: the shapes are exact here but Flow doesn't like constructors
239
- return new FiberNode(tag, pendingProps, key, internalContextTag);
236
+ return new FiberNode(tag, pendingProps, key, mode);
237
};
238
239
function shouldConstruct(Component) {
@@ -260,7 +257,7 @@ export function createWorkInProgress(
257
current.tag,
258
pendingProps,
259
current.key,
263
- current.internalContextTag,
260
+ current.mode,
261
);
262
workInProgress.type = current.type;
263
workInProgress.stateNode = current.stateNode;
@@ -303,13 +300,13 @@ export function createWorkInProgress(
300
}
301
302
export function createHostRootFiber(isAsync): Fiber {
306
- const internalContextTag = isAsync ? AsyncUpdates | StrictMode : NoContext;
307
- return createFiber(HostRoot, null, null, internalContextTag);
303
+ const mode = isAsync ? AsyncMode | StrictMode : NoContext;
304
+ return createFiber(HostRoot, null, null, mode);
305
}
306
307
export function createFiberFromElement(
308
element: ReactElement,
312
- internalContextTag: TypeOfInternalContext,
309
+ mode: TypeOfMode,
310
expirationTime: ExpirationTime,
311
): Fiber {
312
let owner = null;
@@ -332,13 +329,17 @@ export function createFiberFromElement(
329
case REACT_FRAGMENT_TYPE:
330
return createFiberFromFragment(
331
pendingProps.children,
335
- internalContextTag,
332
+ mode,
333
expirationTime,
334
key,
335
);
336
+ case REACT_ASYNC_MODE_TYPE:
337
+ fiberTag = Mode;
338
+ mode |= AsyncMode | StrictMode;
339
+ break;
340
case REACT_STRICT_MODE_TYPE:
341
fiberTag = Mode;
341
- internalContextTag |= StrictMode;
342
+ mode |= StrictMode;
343
break;
344
case REACT_CALL_TYPE:
345
fiberTag = CallComponent;
@@ -382,7 +383,7 @@ export function createFiberFromElement(
383
}
384
}
385
385
- fiber = createFiber(fiberTag, pendingProps, key, internalContextTag);
386
+ fiber = createFiber(fiberTag, pendingProps, key, mode);
387
fiber.type = type;
388
fiber.expirationTime = expirationTime;
389
@@ -425,21 +426,21 @@ function throwOnInvalidElementType(type, owner) {
426
427
export function createFiberFromFragment(
428
elements: ReactFragment,
428
- internalContextTag: TypeOfInternalContext,
429
+ mode: TypeOfMode,
430
expirationTime: ExpirationTime,
431
key: null | string,
432
): Fiber {
432
- const fiber = createFiber(Fragment, elements, key, internalContextTag);
433
+ const fiber = createFiber(Fragment, elements, key, mode);
434
fiber.expirationTime = expirationTime;
435
return fiber;
436
}
437
438
export function createFiberFromText(
439
content: string,
439
- internalContextTag: TypeOfInternalContext,
440
+ mode: TypeOfMode,
441
expirationTime: ExpirationTime,
442
): Fiber {
442
- const fiber = createFiber(HostText, content, null, internalContextTag);
443
+ const fiber = createFiber(HostText, content, null, mode);
444
fiber.expirationTime = expirationTime;
445
return fiber;
446
}
@@ -452,16 +453,11 @@ export function createFiberFromHostInstanceForDeletion(): Fiber {
453
454
export function createFiberFromPortal(
455
portal: ReactPortal,
455
- internalContextTag: TypeOfInternalContext,
456
+ mode: TypeOfMode,
457
expirationTime: ExpirationTime,
458
): Fiber {
459
const pendingProps = portal.children !== null ? portal.children : [];
459
- const fiber = createFiber(
460
- HostPortal,
461
- pendingProps,
462
- portal.key,
463
- internalContextTag,
464
- );
460
+ const fiber = createFiber(HostPortal, pendingProps, portal.key, mode);
461
fiber.expirationTime = expirationTime;
462
fiber.stateNode = {
463
containerInfo: portal.containerInfo,
packages/react-reconciler/src/ReactFiberBeginWork.js
+4
-4
@@ -67,7 +67,7 @@ import {
67
} from './ReactFiberContext';
68
import {pushProvider} from './ReactFiberNewContext';
69
import {NoWork, Never} from './ReactFiberExpirationTime';
70
-import {AsyncUpdates, StrictMode} from './ReactTypeOfInternalContext';
70
+import {AsyncMode, StrictMode} from './ReactTypeOfMode';
71
import MAX_SIGNED_31_BIT_INT from './maxSigned31BitInt';
72
73
let didWarnAboutBadClass;
@@ -293,7 +293,7 @@ export default function<T, P, I, TI, HI, PI, C, CC, CX, PL>(
293
if (
294
debugRenderPhaseSideEffects ||
295
(debugRenderPhaseSideEffectsForStrictMode &&
296
- workInProgress.internalContextTag & StrictMode)
296
+ workInProgress.mode & StrictMode)
297
) {
298
instance.render();
299
}
@@ -302,7 +302,7 @@ export default function<T, P, I, TI, HI, PI, C, CC, CX, PL>(
302
if (
303
debugRenderPhaseSideEffects ||
304
(debugRenderPhaseSideEffectsForStrictMode &&
305
- workInProgress.internalContextTag & StrictMode)
305
+ workInProgress.mode & StrictMode)
306
) {
307
instance.render();
308
}
@@ -438,7 +438,7 @@ export default function<T, P, I, TI, HI, PI, C, CC, CX, PL>(
438
// Check the host config to see if the children are offscreen/hidden.
439
if (
440
renderExpirationTime !== Never &&
441
- workInProgress.internalContextTag & AsyncUpdates &&
441
+ workInProgress.mode & AsyncMode &&
442
shouldDeprioritizeSubtree(type, nextProps)
443
) {
444
// Down-prioritize the children.
packages/react-reconciler/src/ReactFiberClassComponent.js
+4
-16
@@ -14,7 +14,6 @@ import {Update} from 'shared/ReactTypeOfSideEffect';
14
import {
15
debugRenderPhaseSideEffects,
16
debugRenderPhaseSideEffectsForStrictMode,
17
- enableAsyncSubtreeAPI,
17
warnAboutDeprecatedLifecycles,
18
} from 'shared/ReactFeatureFlags';
19
import ReactStrictModeWarnings from './ReactStrictModeWarnings';
@@ -27,7 +26,7 @@ import invariant from 'fbjs/lib/invariant';
26
import warning from 'fbjs/lib/warning';
27
28
import {startPhaseTimer, stopPhaseTimer} from './ReactDebugFiberPerf';
30
-import {AsyncUpdates, StrictMode} from './ReactTypeOfInternalContext';
29
+import {StrictMode} from './ReactTypeOfMode';
30
import {
31
cacheContext,
32
getMaskedContext,
@@ -395,7 +394,7 @@ export default function(
394
if (
395
debugRenderPhaseSideEffects ||
396
(debugRenderPhaseSideEffectsForStrictMode &&
398
- workInProgress.internalContextTag & StrictMode)
397
+ workInProgress.mode & StrictMode)
398
) {
399
new ctor(props, context); // eslint-disable-line no-new
400
}
@@ -548,7 +547,7 @@ export default function(
547
if (
548
debugRenderPhaseSideEffects ||
549
(debugRenderPhaseSideEffectsForStrictMode &&
551
- workInProgress.internalContextTag & StrictMode)
550
+ workInProgress.mode & StrictMode)
551
) {
552
// Invoke method an extra time to help detect side-effects.
553
type.getDerivedStateFromProps.call(
@@ -603,19 +602,8 @@ export default function(
602
instance.refs = emptyObject;
603
instance.context = getMaskedContext(workInProgress, unmaskedContext);
604
606
- if (workInProgress.type != null && workInProgress.type.prototype != null) {
607
- const prototype = workInProgress.type.prototype;
608
-
609
- if (enableAsyncSubtreeAPI) {
610
- if (prototype.unstable_isAsyncReactComponent === true) {
611
- workInProgress.internalContextTag |= AsyncUpdates;
612
- workInProgress.internalContextTag |= StrictMode;
613
- }
614
- }
615
- }
616
-
605
if (__DEV__) {
618
- if (workInProgress.internalContextTag & StrictMode) {
606
+ if (workInProgress.mode & StrictMode) {
607
ReactStrictModeWarnings.recordUnsafeLifecycleWarnings(
608
workInProgress,
609
instance,
packages/react-reconciler/src/ReactFiberScheduler.js
+2
-2
@@ -81,7 +81,7 @@ import {
81
expirationTimeToMs,
82
computeExpirationBucket,
83
} from './ReactFiberExpirationTime';
84
-import {AsyncUpdates} from './ReactTypeOfInternalContext';
84
+import {AsyncMode} from './ReactTypeOfMode';
85
import {getUpdateExpirationTime} from './ReactFiberUpdateQueue';
86
import {resetContext as resetLegacyContext} from './ReactFiberContext';
87
import {resetProviderStack} from './ReactFiberNewContext';
@@ -1200,7 +1200,7 @@ export default function<T, P, I, TI, HI, PI, C, CC, CX, PL>(
1200
} else {
1201
// No explicit expiration context was set, and we're not currently
1202
// performing work. Calculate a new expiration time.
1203
- if (fiber.internalContextTag & AsyncUpdates) {
1203
+ if (fiber.mode & AsyncMode) {
1204
// This is an async update
1205
expirationTime = computeAsyncExpiration();
1206
} else {
packages/react-reconciler/src/ReactFiberUpdateQueue.js
+2
-2
@@ -18,7 +18,7 @@ import {Callback as CallbackEffect} from 'shared/ReactTypeOfSideEffect';
18
import {ClassComponent, HostRoot} from 'shared/ReactTypeOfWork';
19
import invariant from 'fbjs/lib/invariant';
20
import warning from 'fbjs/lib/warning';
21
-import {StrictMode} from './ReactTypeOfInternalContext';
21
+import {StrictMode} from './ReactTypeOfMode';
22
23
import {NoWork} from './ReactFiberExpirationTime';
24
@@ -278,7 +278,7 @@ export function processUpdateQueue<State>(
278
if (
279
debugRenderPhaseSideEffects ||
280
(debugRenderPhaseSideEffectsForStrictMode &&
281
- workInProgress.internalContextTag & StrictMode)
281
+ workInProgress.mode & StrictMode)
282
) {
283
getStateFromUpdate(update, instance, state, props);
284
}
packages/react-reconciler/src/ReactStrictModeWarnings.js
+2
-2
@@ -11,7 +11,7 @@ import type {Fiber} from './ReactFiber';
11
12
import getComponentName from 'shared/getComponentName';
13
import {getStackAddendumByWorkInProgressFiber} from 'shared/ReactFiberComponentTreeHook';
14
-import {StrictMode} from './ReactTypeOfInternalContext';
14
+import {StrictMode} from './ReactTypeOfMode';
15
import warning from 'fbjs/lib/warning';
16
17
type LIFECYCLE =
@@ -104,7 +104,7 @@ if (__DEV__) {
104
let maybeStrictRoot = null;
105
106
while (fiber !== null) {
107
- if (fiber.internalContextTag & StrictMode) {
107
+ if (fiber.mode & StrictMode) {
108
maybeStrictRoot = fiber;
109
}
110
packages/react-reconciler/src/ReactTypeOfMode.js
renamed
+4
-4
@@ -7,8 +7,8 @@
7
* @flow
8
*/
9
10
-export type TypeOfInternalContext = number;
10
+export type TypeOfMode = number;
11
12
-export const NoContext = 0b00000000;
13
-export const AsyncUpdates = 0b00000001;
14
-export const StrictMode = 0b00000010;
12
+export const NoContext = 0b00;
13
+export const AsyncMode = 0b01;
14
+export const StrictMode = 0b10;
packages/react/src/React.js
+7
-3
@@ -7,9 +7,13 @@
7
8
import assign from 'object-assign';
9
import ReactVersion from 'shared/ReactVersion';
10
-import {REACT_FRAGMENT_TYPE, REACT_STRICT_MODE_TYPE} from 'shared/ReactSymbols';
10
+import {
11
+ REACT_FRAGMENT_TYPE,
12
+ REACT_STRICT_MODE_TYPE,
13
+ REACT_ASYNC_MODE_TYPE,
14
+} from 'shared/ReactSymbols';
15
12
-import {AsyncComponent, Component, PureComponent} from './ReactBaseClasses';
16
+import {Component, PureComponent} from './ReactBaseClasses';
17
import {forEach, map, count, toArray, only} from './ReactChildren';
18
import ReactCurrentOwner from './ReactCurrentOwner';
19
import {
@@ -38,10 +42,10 @@ const React = {
42
43
Component,
44
PureComponent,
41
- unstable_AsyncComponent: AsyncComponent,
45
46
Fragment: REACT_FRAGMENT_TYPE,
47
StrictMode: REACT_STRICT_MODE_TYPE,
48
+ unstable_AsyncMode: REACT_ASYNC_MODE_TYPE,
49
50
createElement: __DEV__ ? createElementWithValidation : createElement,
51
cloneElement: __DEV__ ? cloneElementWithValidation : cloneElement,
packages/react/src/ReactBaseClasses.js
+1
-20
@@ -136,23 +136,4 @@ pureComponentPrototype.constructor = PureComponent;
136
Object.assign(pureComponentPrototype, Component.prototype);
137
pureComponentPrototype.isPureReactComponent = true;
138
139
-/**
140
- * Special component type that opts subtree into async rendering mode.
141
- */
142
-function AsyncComponent(props, context, updater) {
143
- this.props = props;
144
- this.context = context;
145
- this.refs = emptyObject;
146
- this.updater = updater || ReactNoopUpdateQueue;
147
-}
148
-
149
-const asyncComponentPrototype = (AsyncComponent.prototype = new ComponentDummy());
150
-asyncComponentPrototype.constructor = AsyncComponent;
151
-// Avoid an extra prototype jump for these methods.
152
-Object.assign(asyncComponentPrototype, Component.prototype);
153
-asyncComponentPrototype.unstable_isAsyncReactComponent = true;
154
-asyncComponentPrototype.render = function() {
155
- return this.props.children;
156
-};
157
-
158
-export {AsyncComponent, Component, PureComponent};
139
+export {Component, PureComponent};
packages/react/src/ReactElementValidator.js
+2
@@ -19,6 +19,7 @@ import {
19
getIteratorFn,
20
REACT_FRAGMENT_TYPE,
21
REACT_STRICT_MODE_TYPE,
22
+ REACT_ASYNC_MODE_TYPE,
23
} from 'shared/ReactSymbols';
24
import checkPropTypes from 'prop-types/checkPropTypes';
25
import warning from 'fbjs/lib/warning';
@@ -287,6 +288,7 @@ export function createElementWithValidation(type, props, children) {
288
typeof type === 'function' ||
289
// Note: its typeof might be other than 'symbol' or 'number' if it's a polyfill.
290
type === REACT_FRAGMENT_TYPE ||
291
+ type === REACT_ASYNC_MODE_TYPE ||
292
type === REACT_STRICT_MODE_TYPE;
293
294
// We warn in this case but don't throw. We expect the element creation to
packages/react/src/__tests__/ReactStrictMode-test.internal.js
+36
-18
@@ -285,10 +285,14 @@ describe('ReactStrictMode', () => {
285
UNSAFE_componentWillUpdate() {}
286
UNSAFE_componentWillReceiveProps() {}
287
render() {
288
- return <AsyncRoot />;
288
+ return (
289
+ <React.unstable_AsyncMode>
290
+ <AsyncRoot />
291
+ </React.unstable_AsyncMode>
292
+ );
293
}
294
}
291
- class AsyncRoot extends React.unstable_AsyncComponent {
295
+ class AsyncRoot extends React.Component {
296
UNSAFE_componentWillMount() {}
297
UNSAFE_componentWillUpdate() {}
298
render() {
@@ -326,7 +330,6 @@ describe('ReactStrictMode', () => {
330
rendered = ReactTestRenderer.create(<SyncRoot />);
331
}).toWarnDev(
332
'Unsafe lifecycle methods were found within a strict-mode tree:' +
329
- '\n in AsyncRoot (at **)' +
333
'\n in SyncRoot (at **)' +
334
'\n\ncomponentWillMount: Please update the following components ' +
335
'to use componentDidMount instead: AsyncRoot' +
@@ -349,10 +352,14 @@ describe('ReactStrictMode', () => {
352
UNSAFE_componentWillUpdate() {}
353
UNSAFE_componentWillReceiveProps() {}
354
render() {
352
- return <AsyncRoot />;
355
+ return (
356
+ <React.unstable_AsyncMode>
357
+ <AsyncRoot />
358
+ </React.unstable_AsyncMode>
359
+ );
360
}
361
}
355
- class AsyncRoot extends React.unstable_AsyncComponent {
362
+ class AsyncRoot extends React.Component {
363
UNSAFE_componentWillMount() {}
364
UNSAFE_componentWillUpdate() {}
365
render() {
@@ -380,7 +387,6 @@ describe('ReactStrictMode', () => {
387
() => (rendered = ReactTestRenderer.create(<SyncRoot />)),
388
).toWarnDev(
389
'Unsafe lifecycle methods were found within a strict-mode tree:' +
383
- '\n in AsyncRoot (at **)' +
390
'\n in SyncRoot (at **)' +
391
'\n\ncomponentWillMount: Please update the following components ' +
392
'to use componentDidMount instead: AsyncRoot, Parent' +
@@ -411,21 +417,25 @@ describe('ReactStrictMode', () => {
417
);
418
}
419
}
414
- class AsyncRootOne extends React.unstable_AsyncComponent {
420
+ class AsyncRootOne extends React.Component {
421
render() {
422
return (
417
- <Foo>
418
- <Bar />
419
- </Foo>
423
+ <React.unstable_AsyncMode>
424
+ <Foo>
425
+ <Bar />
426
+ </Foo>
427
+ </React.unstable_AsyncMode>
428
);
429
}
430
}
423
- class AsyncRootTwo extends React.unstable_AsyncComponent {
431
+ class AsyncRootTwo extends React.Component {
432
render() {
433
return (
426
- <Foo>
427
- <Baz />
428
- </Foo>
434
+ <React.unstable_AsyncMode>
435
+ <Foo>
436
+ <Baz />
437
+ </Foo>
438
+ </React.unstable_AsyncMode>
439
);
440
}
441
}
@@ -473,9 +483,13 @@ describe('ReactStrictMode', () => {
483
});
484
485
it('should warn about components not present during the initial render', () => {
476
- class AsyncRoot extends React.unstable_AsyncComponent {
486
+ class AsyncRoot extends React.Component {
487
render() {
478
- return this.props.foo ? <Foo /> : <Bar />;
488
+ return (
489
+ <React.unstable_AsyncMode>
490
+ {this.props.foo ? <Foo /> : <Bar />}
491
+ </React.unstable_AsyncMode>
492
+ );
493
}
494
}
495
class Foo extends React.Component {
@@ -520,9 +534,13 @@ describe('ReactStrictMode', () => {
534
it('should not warn about uncommitted lifecycles in the event of an error', () => {
535
let caughtError;
536
523
- class AsyncRoot extends React.unstable_AsyncComponent {
537
+ class AsyncRoot extends React.Component {
538
render() {
525
- return <ErrorBoundary />;
539
+ return (
540
+ <React.unstable_AsyncMode>
541
+ <ErrorBoundary />
542
+ </React.unstable_AsyncMode>
543
+ );
544
}
545
}
546
class ErrorBoundary extends React.Component {
packages/shared/ReactFeatureFlags.js
-1
@@ -9,7 +9,6 @@
9
10
import invariant from 'fbjs/lib/invariant';
11
12
-export const enableAsyncSubtreeAPI = true;
12
// Exports ReactDOM.createRoot
13
export const enableCreateRoot = false;
14
export const enableUserTimingAPI = __DEV__;
packages/shared/ReactSymbols.js
+3
@@ -33,6 +33,9 @@ export const REACT_PROVIDER_TYPE = hasSymbol
33
export const REACT_CONTEXT_TYPE = hasSymbol
34
? Symbol.for('react.context')
35
: 0xeace;
36
+export const REACT_ASYNC_MODE_TYPE = hasSymbol
37
+ ? Symbol.for('react.async_mode')
38
+ : 0xeacf;
39
40
const MAYBE_ITERATOR_SYMBOL = typeof Symbol === 'function' && Symbol.iterator;
41
const FAUX_ITERATOR_SYMBOL = '@@iterator';
packages/shared/forks/ReactFeatureFlags.native-fabric.js
-1
@@ -14,7 +14,6 @@ import typeof * as FabricFeatureFlagsType from './ReactFeatureFlags.native-fabri
14
15
export const debugRenderPhaseSideEffects = false;
16
export const debugRenderPhaseSideEffectsForStrictMode = false;
17
-export const enableAsyncSubtreeAPI = true;
17
export const enableCreateRoot = false;
18
export const enableUserTimingAPI = __DEV__;
19
export const warnAboutDeprecatedLifecycles = false;
packages/shared/forks/ReactFeatureFlags.native.js
-1
@@ -20,7 +20,6 @@ export const {
20
} = require('ReactFeatureFlags');
21
22
// The rest of the flags are static for better dead code elimination.
23
-export const enableAsyncSubtreeAPI = true;
23
export const enableCreateRoot = false;
24
export const enableUserTimingAPI = __DEV__;
25
export const enableMutatingReconciler = true;
packages/shared/forks/ReactFeatureFlags.www.js
-1
@@ -18,7 +18,6 @@ export const {
18
} = require('ReactFeatureFlags');
19
20
// The rest of the flags are static for better dead code elimination.
21
-export const enableAsyncSubtreeAPI = true;
21
export const enableCreateRoot = true;
22
export const enableNewContextAPI = true;
23