@samitouri / QOS-React-2 / commits / 0c896ffe6b

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');