@samitouri / QOS-React / commits / 648d6e190c

Swap .child and .stateNode in coroutines

It is slightly more useful this way because when we want to find host nodes we typically want to do so in the second phase. That's the real tree where as the first phase is more of a virtual part of the tree.

Sebastian Markbage committed Jan 20, 2017 at 22:21 UTC 648d6e190cf44870ab62a0e8a65189975ef44ee6
7 files changed +60 -17
src/renderers/shared/fiber/ReactFiberBeginWork.js
+40 -2
@@ -518,11 +518,49 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
518 } else if (nextCoroutine === null || workInProgress.memoizedProps === nextCoroutine) {
519 return bailoutOnAlreadyFinishedWork(current, workInProgress);
520 }
521 - reconcileChildren(current, workInProgress, nextCoroutine.children);
521 +
522 + const nextChildren = nextCoroutine.children;
523 + const priorityLevel = workInProgress.pendingWorkPriority;
524 +
525 + // The following is a fork of reconcileChildrenAtPriority but using
526 + // stateNode to store the child.
527 +
528 + // At this point any memoization is no longer valid since we'll have changed
529 + // the children.
530 + workInProgress.memoizedProps = null;
531 + if (!current) {
532 + workInProgress.stateNode = mountChildFibersInPlace(
533 + workInProgress,
534 + workInProgress.stateNode,
535 + nextChildren,
536 + priorityLevel
537 + );
538 + } else if (current.child === workInProgress.child) {
539 + clearDeletions(workInProgress);
540 +
541 + workInProgress.stateNode = reconcileChildFibers(
542 + workInProgress,
543 + workInProgress.stateNode,
544 + nextChildren,
545 + priorityLevel
546 + );
547 +
548 + transferDeletions(workInProgress);
549 + } else {
550 + workInProgress.stateNode = reconcileChildFibersInPlace(
551 + workInProgress,
552 + workInProgress.stateNode,
553 + nextChildren,
554 + priorityLevel
555 + );
556 +
557 + transferDeletions(workInProgress);
558 + }
559 +
560 memoizeProps(workInProgress, nextCoroutine);
561 // This doesn't take arbitrary time so we could synchronously just begin
562 // eagerly do the work of workInProgress.child as an optimization.
525 - return workInProgress.child;
563 + return workInProgress.stateNode;
564 }
565
566 function updatePortalComponent(current, workInProgress) {
src/renderers/shared/fiber/ReactFiberCommitWork.js
-4
@@ -136,7 +136,6 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
136 while (node.tag !== HostComponent && node.tag !== HostText) {
137 // If it is not host node and, we might have a host node inside it.
138 // Try to search down until we find one.
139 - // TODO: For coroutines, this will have to search the stateNode.
139 if (node.effectTag & Placement) {
140 // If we don't have a child, try the siblings instead.
141 continue siblings;
@@ -198,7 +197,6 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
197 // down its children. Instead, we'll get insertions from each child in
198 // the portal directly.
199 } else if (node.child) {
201 - // TODO: Coroutines need to visit the stateNode.
200 node.child.return = node;
201 node = node.child;
202 continue;
@@ -229,7 +227,6 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
227 // Visit children because they may contain more composite or host nodes.
228 // Skip portals because commitUnmount() currently visits them recursively.
229 if (node.child && node.tag !== HostPortal) {
232 - // TODO: Coroutines need to visit the stateNode.
230 node.child.return = node;
231 node = node.child;
232 continue;
@@ -273,7 +270,6 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
270 commitUnmount(node);
271 // Visit children because we may find more host components below.
272 if (node.child) {
276 - // TODO: Coroutines need to visit the stateNode.
273 node.child.return = node;
274 node = node.child;
275 continue;
src/renderers/shared/fiber/ReactFiberCompleteWork.js
+17 -6
@@ -66,6 +66,18 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
66 popHostContainer,
67 } = hostContext;
68
69 + function markChildAsProgressed(current, workInProgress, priorityLevel) {
70 + // We now have clones. Let's store them as the currently progressed work.
71 + workInProgress.progressedChild = workInProgress.child;
72 + workInProgress.progressedPriority = priorityLevel;
73 + if (current) {
74 + // We also store it on the current. When the alternate swaps in we can
75 + // continue from this point.
76 + current.progressedChild = workInProgress.progressedChild;
77 + current.progressedPriority = workInProgress.progressedPriority;
78 + }
79 + }
80 +
81 function markUpdate(workInProgress : Fiber) {
82 // Tag the fiber with an update effect. This turns a Placement into
83 // an UpdateAndPlacement.
@@ -73,7 +85,7 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
85 }
86
87 function appendAllYields(yields : Array<ReifiedYield>, workInProgress : Fiber) {
76 - let node = workInProgress.child;
88 + let node = workInProgress.stateNode;
89 while (node) {
90 if (node.tag === HostComponent || node.tag === HostText ||
91 node.tag === HostPortal) {
@@ -81,7 +93,6 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
93 } else if (node.tag === YieldComponent) {
94 yields.push(node.type);
95 } else if (node.child) {
84 - // TODO: Coroutines need to visit the stateNode.
96 node.child.return = node;
97 node = node.child;
98 continue;
@@ -123,16 +134,17 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
134 var props = coroutine.props;
135 var nextChildren = fn(props, yields);
136
126 - var currentFirstChild = current ? current.stateNode : null;
137 + var currentFirstChild = current ? current.child : null;
138 // Inherit the priority of the returnFiber.
139 const priority = workInProgress.pendingWorkPriority;
129 - workInProgress.stateNode = reconcileChildFibers(
140 + workInProgress.child = reconcileChildFibers(
141 workInProgress,
142 currentFirstChild,
143 nextChildren,
144 priority
145 );
135 - return workInProgress.stateNode;
146 + markChildAsProgressed(current, workInProgress, priority);
147 + return workInProgress.child;
148 }
149
150 function appendAllChildren(parent : I, workInProgress : Fiber) {
@@ -147,7 +159,6 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
159 // down its children. Instead, we'll get insertions from each child in
160 // the portal directly.
161 } else if (node.child) {
150 - // TODO: Coroutines need to visit the stateNode.
162 node = node.child;
163 continue;
164 }
src/renderers/shared/fiber/ReactFiberScheduler.js
+2
@@ -435,6 +435,8 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(config : HostConfig<T, P,
435 newPriority = getPendingPriority(queue);
436 }
437
438 + // TODO: Coroutines need to visit stateNode
439 +
440 // progressedChild is going to be the child set with the highest priority.
441 // Either it is the same as child, or it just bailed out because it choose
442 // not to do the work.
src/renderers/shared/fiber/ReactFiberTreeReflection.js
-1
@@ -168,7 +168,6 @@ exports.findCurrentHostFiber = function(parent : Fiber) : Fiber | null {
168 return node;
169 } else if (node.child) {
170 // TODO: If we hit a Portal, we're supposed to skip it.
171 - // TODO: Coroutines need to visit the stateNode.
171 node.child.return = node;
172 node = node.child;
173 continue;
src/renderers/shared/fiber/__tests__/ReactCoroutine-test.js
+1 -3
@@ -146,10 +146,8 @@ describe('ReactCoroutine', () => {
146
147 expect(ops).toEqual([
148 'Unmount Parent',
149 - // TODO: This should happen in the order Child, Continuation which it
150 - // will once we swap stateNode and child positions of these.
151 - 'Unmount Continuation',
149 'Unmount Child',
150 + 'Unmount Continuation',
151 ]);
152
153 });
src/test/ReactTestUtils.js
-1
@@ -97,7 +97,6 @@ function findAllInRenderedFiberTreeInternal(fiber, test) {
97 }
98 }
99 if (node.child) {
100 - // TODO: Coroutines need to visit the stateNode.
100 node.child.return = node;
101 node = node.child;
102 continue;