Change unstable_asyncUpdates from an instance to a static property
This lets us check for its existence before the instance is constructed. Also works with functional components.
Andrew Clark committed
Apr 18, 2017 at 16:10 UTC
0c896ffe6ba840887a3bacfb7d923e33e78d09de
5 files changed
+135
-73
scripts/fiber/tests-passing.txt
+2
-2
@@ -752,10 +752,10 @@ src/renderers/dom/fiber/__tests__/ReactDOMFiber-test.js
752
src/renderers/dom/fiber/__tests__/ReactDOMFiberAsync-test.js
753
* renders synchronously by default
754
* throws when calling async APIs when feature flag is disabled
755
-* unstable_asyncRender creates an async tree
756
-* updates inside an async tree are async by default
755
* unstable_asyncUpdates creates an async subtree
756
* updates inside an async subtree are async by default
757
+* unstable_asyncUpdates at the root makes the entire tree async
758
+* updates inside an async tree are async by default
759
760
src/renderers/dom/shared/__tests__/CSSProperty-test.js
761
* should generate browser prefixes for its `isUnitlessNumber`
src/renderers/dom/fiber/__tests__/ReactDOMFiberAsync-test.js
+10
-15
@@ -59,12 +59,10 @@ describe('ReactDOMFiberAsync', () => {
59
});
60
61
it('updates inside an async subtree are async by default', () => {
62
- class Component extends React.Component {
63
- static unstable_asyncUpdates = true;
64
- render() {
65
- return <Child />;
66
- }
62
+ function Component(props) {
63
+ return <Child />;
64
}
65
+ Component.unstable_asyncUpdates = true;
66
67
let instance;
68
class Child extends React.Component {
@@ -85,12 +83,10 @@ describe('ReactDOMFiberAsync', () => {
83
});
84
85
it('unstable_asyncUpdates at the root makes the entire tree async', () => {
88
- class Async extends React.Component {
89
- static unstable_asyncUpdates = true;
90
- render() {
91
- return this.props.children;
92
- }
86
+ function Async(props) {
87
+ return props.children;
88
}
89
+ Async.unstable_asyncUpdates = true;
90
ReactDOM.render(<Async><div>Hi</div></Async>, container);
91
expect(container.textContent).toEqual('');
92
jest.runAllTimers();
@@ -103,12 +99,11 @@ describe('ReactDOMFiberAsync', () => {
99
});
100
101
it('updates inside an async tree are async by default', () => {
106
- class Async extends React.Component {
107
- static unstable_asyncUpdates = true;
108
- render() {
109
- return this.props.children;
110
- }
102
+ function Async(props) {
103
+ return props.children;
104
}
105
+ Async.unstable_asyncUpdates = true;
106
+
107
let instance;
108
class Component extends React.Component {
109
state = {step: 0};
src/renderers/shared/fiber/ReactChildFiber.js
+85
-34
@@ -305,9 +305,12 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
305
) {
306
if (current === null || current.tag !== HostText) {
307
// Insert
308
- const created = createFiberFromText(textContent, priority);
308
+ const created = createFiberFromText(
309
+ textContent,
310
+ returnFiber.internalContextTag,
311
+ priority,
312
+ );
313
created.return = returnFiber;
310
- created.internalContextTag = returnFiber.internalContextTag;
314
return created;
315
} else {
316
// Update
@@ -326,10 +329,13 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
329
): Fiber {
330
if (current === null || current.type !== element.type) {
331
// Insert
329
- const created = createFiberFromElement(element, priority);
332
+ const created = createFiberFromElement(
333
+ element,
334
+ returnFiber.internalContextTag,
335
+ priority,
336
+ );
337
created.ref = coerceRef(current, element);
338
created.return = returnFiber;
332
- created.internalContextTag = returnFiber.internalContextTag;
339
return created;
340
} else {
341
// Move based on index
@@ -354,9 +360,12 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
360
// TODO: Should this also compare handler to determine whether to reuse?
361
if (current === null || current.tag !== CoroutineComponent) {
362
// Insert
357
- const created = createFiberFromCoroutine(coroutine, priority);
363
+ const created = createFiberFromCoroutine(
364
+ coroutine,
365
+ returnFiber.internalContextTag,
366
+ priority,
367
+ );
368
created.return = returnFiber;
359
- created.internalContextTag = returnFiber.internalContextTag;
369
return created;
370
} else {
371
// Move based on index
@@ -375,10 +384,13 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
384
): Fiber {
385
if (current === null || current.tag !== YieldComponent) {
386
// Insert
378
- const created = createFiberFromYield(yieldNode, priority);
387
+ const created = createFiberFromYield(
388
+ yieldNode,
389
+ returnFiber.internalContextTag,
390
+ priority,
391
+ );
392
created.type = yieldNode.value;
393
created.return = returnFiber;
381
- created.internalContextTag = returnFiber.internalContextTag;
394
return created;
395
} else {
396
// Move based on index
@@ -402,9 +414,12 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
414
current.stateNode.implementation !== portal.implementation
415
) {
416
// Insert
405
- const created = createFiberFromPortal(portal, priority);
417
+ const created = createFiberFromPortal(
418
+ portal,
419
+ returnFiber.internalContextTag,
420
+ priority,
421
+ );
422
created.return = returnFiber;
407
- created.internalContextTag = returnFiber.internalContextTag;
423
return created;
424
} else {
425
// Update
@@ -423,9 +438,12 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
438
): Fiber {
439
if (current === null || current.tag !== Fragment) {
440
// Insert
426
- const created = createFiberFromFragment(fragment, priority);
441
+ const created = createFiberFromFragment(
442
+ fragment,
443
+ returnFiber.internalContextTag,
444
+ priority,
445
+ );
446
created.return = returnFiber;
428
- created.internalContextTag = returnFiber.internalContextTag;
447
return created;
448
} else {
449
// Update
@@ -445,49 +463,67 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
463
// Text nodes doesn't have keys. If the previous node is implicitly keyed
464
// we can continue to replace it without aborting even if it is not a text
465
// node.
448
- const created = createFiberFromText('' + newChild, priority);
466
+ const created = createFiberFromText(
467
+ '' + newChild,
468
+ returnFiber.internalContextTag,
469
+ priority,
470
+ );
471
created.return = returnFiber;
450
- created.internalContextTag = returnFiber.internalContextTag;
472
return created;
473
}
474
475
if (typeof newChild === 'object' && newChild !== null) {
476
switch (newChild.$$typeof) {
477
case REACT_ELEMENT_TYPE: {
457
- const created = createFiberFromElement(newChild, priority);
478
+ const created = createFiberFromElement(
479
+ newChild,
480
+ returnFiber.internalContextTag,
481
+ priority,
482
+ );
483
created.ref = coerceRef(null, newChild);
484
created.return = returnFiber;
460
- created.internalContextTag = returnFiber.internalContextTag;
485
return created;
486
}
487
488
case REACT_COROUTINE_TYPE: {
465
- const created = createFiberFromCoroutine(newChild, priority);
489
+ const created = createFiberFromCoroutine(
490
+ newChild,
491
+ returnFiber.internalContextTag,
492
+ priority,
493
+ );
494
created.return = returnFiber;
467
- created.internalContextTag = returnFiber.internalContextTag;
495
return created;
496
}
497
498
case REACT_YIELD_TYPE: {
472
- const created = createFiberFromYield(newChild, priority);
499
+ const created = createFiberFromYield(
500
+ newChild,
501
+ returnFiber.internalContextTag,
502
+ priority,
503
+ );
504
created.type = newChild.value;
505
created.return = returnFiber;
475
- created.internalContextTag = returnFiber.internalContextTag;
506
return created;
507
}
508
509
case REACT_PORTAL_TYPE: {
480
- const created = createFiberFromPortal(newChild, priority);
510
+ const created = createFiberFromPortal(
511
+ newChild,
512
+ returnFiber.internalContextTag,
513
+ priority,
514
+ );
515
created.return = returnFiber;
482
- created.internalContextTag = returnFiber.internalContextTag;
516
return created;
517
}
518
}
519
520
if (isArray(newChild) || getIteratorFn(newChild)) {
488
- const created = createFiberFromFragment(newChild, priority);
521
+ const created = createFiberFromFragment(
522
+ newChild,
523
+ returnFiber.internalContextTag,
524
+ priority,
525
+ );
526
created.return = returnFiber;
490
- created.internalContextTag = returnFiber.internalContextTag;
527
return created;
528
}
529
@@ -1023,9 +1059,12 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
1059
// The existing first child is not a text node so we need to create one
1060
// and delete the existing ones.
1061
deleteRemainingChildren(returnFiber, currentFirstChild);
1026
- const created = createFiberFromText(textContent, priority);
1062
+ const created = createFiberFromText(
1063
+ textContent,
1064
+ returnFiber.internalContextTag,
1065
+ priority,
1066
+ );
1067
created.return = returnFiber;
1028
- created.internalContextTag = returnFiber.internalContextTag;
1068
return created;
1069
}
1070
@@ -1062,10 +1101,13 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
1101
child = child.sibling;
1102
}
1103
1065
- const created = createFiberFromElement(element, priority);
1104
+ const created = createFiberFromElement(
1105
+ element,
1106
+ returnFiber.internalContextTag,
1107
+ priority,
1108
+ );
1109
created.ref = coerceRef(currentFirstChild, element);
1110
created.return = returnFiber;
1068
- created.internalContextTag = returnFiber.internalContextTag;
1111
return created;
1112
}
1113
@@ -1097,9 +1139,12 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
1139
child = child.sibling;
1140
}
1141
1100
- const created = createFiberFromCoroutine(coroutine, priority);
1142
+ const created = createFiberFromCoroutine(
1143
+ coroutine,
1144
+ returnFiber.internalContextTag,
1145
+ priority,
1146
+ );
1147
created.return = returnFiber;
1102
- created.internalContextTag = returnFiber.internalContextTag;
1148
return created;
1149
}
1150
@@ -1123,10 +1168,13 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
1168
}
1169
}
1170
1126
- const created = createFiberFromYield(yieldNode, priority);
1171
+ const created = createFiberFromYield(
1172
+ yieldNode,
1173
+ returnFiber.internalContextTag,
1174
+ priority,
1175
+ );
1176
created.type = yieldNode.value;
1177
created.return = returnFiber;
1129
- created.internalContextTag = returnFiber.internalContextTag;
1178
return created;
1179
}
1180
@@ -1162,9 +1210,12 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
1210
child = child.sibling;
1211
}
1212
1165
- const created = createFiberFromPortal(portal, priority);
1213
+ const created = createFiberFromPortal(
1214
+ portal,
1215
+ returnFiber.internalContextTag,
1216
+ priority,
1217
+ );
1218
created.return = returnFiber;
1167
- created.internalContextTag = returnFiber.internalContextTag;
1219
return created;
1220
}
1221
src/renderers/shared/fiber/ReactFiber.js
+38
-15
@@ -39,6 +39,7 @@ var {NoWork} = require('ReactPriorityLevel');
39
40
var {
41
NoContext,
42
+ AsyncUpdates,
43
} = require('ReactTypeOfInternalContext');
44
45
var {
@@ -184,7 +185,11 @@ if (__DEV__) {
185
// to optimize in a non-JIT environment.
186
// 5) It should be easy to port this to a C struct and keep a C implementation
187
// compatible.
187
-var createFiber = function(tag: TypeOfWork, key: null | string): Fiber {
188
+var createFiber = function(
189
+ tag: TypeOfWork,
190
+ key: null | string,
191
+ internalContextTag: TypeOfInternalContext,
192
+): Fiber {
193
var fiber: Fiber = {
194
// Instance
195
@@ -211,7 +216,7 @@ var createFiber = function(tag: TypeOfWork, key: null | string): Fiber {
216
updateQueue: null,
217
memoizedState: null,
218
214
- internalContextTag: NoContext,
219
+ internalContextTag,
220
221
effectTag: NoEffect,
222
nextEffect: null,
@@ -274,7 +279,7 @@ exports.cloneFiber = function(
279
alt.lastEffect = null;
280
} else {
281
// This should not have an alternate already
277
- alt = createFiber(fiber.tag, fiber.key);
282
+ alt = createFiber(fiber.tag, fiber.key, fiber.internalContextTag);
283
alt.type = fiber.type;
284
285
alt.progressedChild = fiber.progressedChild;
@@ -298,8 +303,6 @@ exports.cloneFiber = function(
303
alt.memoizedProps = fiber.memoizedProps;
304
alt.memoizedState = fiber.memoizedState;
305
301
- alt.internalContextTag = fiber.internalContextTag;
302
-
306
if (__DEV__) {
307
alt._debugID = fiber._debugID;
308
alt._debugSource = fiber._debugSource;
@@ -310,12 +313,13 @@ exports.cloneFiber = function(
313
};
314
315
exports.createHostRootFiber = function(): Fiber {
313
- const fiber = createFiber(HostRoot, null);
316
+ const fiber = createFiber(HostRoot, null, NoContext);
317
return fiber;
318
};
319
320
exports.createFiberFromElement = function(
321
element: ReactElement,
322
+ internalContextTag: TypeOfInternalContext,
323
priorityLevel: PriorityLevel,
324
): Fiber {
325
let owner = null;
@@ -323,7 +327,12 @@ exports.createFiberFromElement = function(
327
owner = element._owner;
328
}
329
326
- const fiber = createFiberFromElementType(element.type, element.key, owner);
330
+ const fiber = createFiberFromElementType(
331
+ element.type,
332
+ element.key,
333
+ internalContextTag,
334
+ owner,
335
+ );
336
fiber.pendingProps = element.props;
337
fiber.pendingWorkPriority = priorityLevel;
338
@@ -337,11 +346,12 @@ exports.createFiberFromElement = function(
346
347
exports.createFiberFromFragment = function(
348
elements: ReactFragment,
349
+ internalContextTag: TypeOfInternalContext,
350
priorityLevel: PriorityLevel,
351
): Fiber {
352
// TODO: Consider supporting keyed fragments. Technically, we accidentally
353
// support that in the existing React.
344
- const fiber = createFiber(Fragment, null);
354
+ const fiber = createFiber(Fragment, null, internalContextTag);
355
fiber.pendingProps = elements;
356
fiber.pendingWorkPriority = priorityLevel;
357
return fiber;
@@ -349,9 +359,10 @@ exports.createFiberFromFragment = function(
359
360
exports.createFiberFromText = function(
361
content: string,
362
+ internalContextTag: TypeOfInternalContext,
363
priorityLevel: PriorityLevel,
364
): Fiber {
354
- const fiber = createFiber(HostText, null);
365
+ const fiber = createFiber(HostText, null, internalContextTag);
366
fiber.pendingProps = content;
367
fiber.pendingWorkPriority = priorityLevel;
368
return fiber;
@@ -360,16 +371,21 @@ exports.createFiberFromText = function(
371
function createFiberFromElementType(
372
type: mixed,
373
key: null | string,
374
+ internalContextTag: TypeOfInternalContext,
375
debugOwner: null | Fiber | ReactInstance,
376
): Fiber {
377
+ if (type != null && (type: any).unstable_asyncUpdates === true) {
378
+ internalContextTag |= AsyncUpdates;
379
+ }
380
+
381
let fiber;
382
if (typeof type === 'function') {
383
fiber = shouldConstruct(type)
368
- ? createFiber(ClassComponent, key)
369
- : createFiber(IndeterminateComponent, key);
384
+ ? createFiber(ClassComponent, key, internalContextTag)
385
+ : createFiber(IndeterminateComponent, key, internalContextTag);
386
fiber.type = type;
387
} else if (typeof type === 'string') {
372
- fiber = createFiber(HostComponent, key);
388
+ fiber = createFiber(HostComponent, key, internalContextTag);
389
fiber.type = type;
390
} else if (
391
typeof type === 'object' &&
@@ -416,9 +432,14 @@ exports.createFiberFromElementType = createFiberFromElementType;
432
433
exports.createFiberFromCoroutine = function(
434
coroutine: ReactCoroutine,
435
+ internalContextTag: TypeOfInternalContext,
436
priorityLevel: PriorityLevel,
437
): Fiber {
421
- const fiber = createFiber(CoroutineComponent, coroutine.key);
438
+ const fiber = createFiber(
439
+ CoroutineComponent,
440
+ coroutine.key,
441
+ internalContextTag,
442
+ );
443
fiber.type = coroutine.handler;
444
fiber.pendingProps = coroutine;
445
fiber.pendingWorkPriority = priorityLevel;
@@ -427,17 +448,19 @@ exports.createFiberFromCoroutine = function(
448
449
exports.createFiberFromYield = function(
450
yieldNode: ReactYield,
451
+ internalContextTag: TypeOfInternalContext,
452
priorityLevel: PriorityLevel,
453
): Fiber {
432
- const fiber = createFiber(YieldComponent, null);
454
+ const fiber = createFiber(YieldComponent, null, internalContextTag);
455
return fiber;
456
};
457
458
exports.createFiberFromPortal = function(
459
portal: ReactPortal,
460
+ internalContextTag: TypeOfInternalContext,
461
priorityLevel: PriorityLevel,
462
): Fiber {
440
- const fiber = createFiber(HostPortal, portal.key);
463
+ const fiber = createFiber(HostPortal, portal.key, internalContextTag);
464
fiber.pendingProps = portal.children || [];
465
fiber.pendingWorkPriority = priorityLevel;
466
fiber.stateNode = {
src/renderers/shared/fiber/ReactFiberClassComponent.js
-7
@@ -15,9 +15,6 @@
15
import type {Fiber} from 'ReactFiber';
16
import type {PriorityLevel} from 'ReactPriorityLevel';
17
18
-var {
19
- AsyncUpdates,
20
-} = require('ReactTypeOfInternalContext');
18
var {
19
Update,
20
} = require('ReactTypeOfSideEffect');
@@ -308,10 +305,6 @@ module.exports = function(
305
instance.refs = emptyObject;
306
instance.context = getMaskedContext(workInProgress, unmaskedContext);
307
311
- if (workInProgress.type.unstable_asyncUpdates === true) {
312
- workInProgress.internalContextTag |= AsyncUpdates;
313
- }
314
-
308
if (typeof instance.componentWillMount === 'function') {
309
if (__DEV__) {
310
startPhaseTimer(workInProgress, 'componentWillMount');