Use the tag instead of stage field for coroutine stages
This gets rid of a field that we only need for coroutines. We might need this if we have multi phase handlers in the future but then maybe we can just use multiple tags.
Sebastian Markbage committed
May 31, 2016 at 13:33 UTC
811084d74e7fefe09383e4ff39ed721b16d6a26f
4 files changed
+38
-39
src/renderers/shared/fiber/ReactFiber.js
-5
@@ -51,9 +51,6 @@ export type Fiber = {
51
// if this returns multiple values. Such as a fragment.
52
output: any, // This type will be more specific once we overload the tag.
53
54
- // Used by multi-stage coroutines.
55
- stage: number, // Consider reusing the tag field instead.
56
-
54
// This will be used to quickly determine if a subtree has no pending changes.
55
hasPendingChanges: bool,
56
@@ -78,8 +75,6 @@ var createFiber = function(tag : number, key : null | string) : Fiber {
75
input: null,
76
output: null,
77
81
- stage: 0,
82
-
78
hasPendingChanges: true,
79
80
stateNode: null,
src/renderers/shared/fiber/ReactFiberBeginWork.js
+5
-2
@@ -23,6 +23,7 @@ var {
23
ClassComponent,
24
HostComponent,
25
CoroutineComponent,
26
+ CoroutineHandlerPhase,
27
YieldComponent,
28
} = ReactTypesOfWork;
29
@@ -97,9 +98,11 @@ function beginWork(unitOfWork : Fiber) : ?Fiber {
98
case HostComponent:
99
updateHostComponent(unitOfWork);
100
break;
101
+ case CoroutineHandlerPhase:
102
+ // This is a restart. Reset the tag to the initial phase.
103
+ unitOfWork.tag = CoroutineComponent;
104
+ // Intentionally fall through since this is now the same.
105
case CoroutineComponent:
101
- // Reset the stage to zero.
102
- unitOfWork.stage = 0;
106
updateCoroutineComponent(unitOfWork);
107
// This doesn't take arbitrary time so we could synchronously just begin
108
// eagerly do the work of unitOfWork.child as an optimization.
src/renderers/shared/fiber/ReactFiberCompleteWork.js
+31
-31
@@ -25,6 +25,7 @@ var {
25
ClassComponent,
26
HostComponent,
27
CoroutineComponent,
28
+ CoroutineHandlerPhase,
29
YieldComponent,
30
} = ReactTypesOfWork;
31
@@ -52,43 +53,37 @@ function recursivelyFillYields(yields, output : ?Fiber | ?ReifiedYield) {
53
}
54
}
55
55
-function handleCoroutine(unitOfWork : Fiber) {
56
+function moveCoroutineToHandlerPhase(unitOfWork : Fiber) {
57
var coroutine = (unitOfWork.input : ?ReactCoroutine);
58
if (!coroutine) {
59
throw new Error('Should be resolved by now');
60
}
61
61
- if (unitOfWork.stage === 0) {
62
- // First step of the coroutine has completed. Now we need to do the second.
63
- // TODO: It would be nice to have a multi stage coroutine represented by a
64
- // single component, or at least tail call optimize nested ones.
65
- // TODO: If we end up not using multi stage coroutines, we could also reuse
66
- // the tag field to switch between the two stages.
67
- unitOfWork.stage = 1;
62
+ // First step of the coroutine has completed. Now we need to do the second.
63
+ // TODO: It would be nice to have a multi stage coroutine represented by a
64
+ // single component, or at least tail call optimize nested ones. Currently
65
+ // that requires additional fields that we don't want to add to the fiber.
66
+ // So this requires nested handlers.
67
+ unitOfWork.tag = CoroutineHandlerPhase;
68
69
- // Build up the yields.
70
- // TODO: Compare this to a generator or opaque helpers like Children.
71
- var yields : Array<ReifiedYield> = [];
72
- var child = unitOfWork.child;
73
- while (child) {
74
- recursivelyFillYields(yields, child.output);
75
- child = child.sibling;
76
- }
77
- var fn = coroutine.handler;
78
- var props = coroutine.props;
79
- var nextChildren = fn(props, yields);
80
-
81
- unitOfWork.stateNode = ReactChildFiber.reconcileChildFibers(
82
- unitOfWork,
83
- unitOfWork.stateNode,
84
- nextChildren
85
- );
86
- return unitOfWork.stateNode;
87
- } else {
88
- // The coroutine is now complete.
89
- transferOutput(unitOfWork.stateNode, unitOfWork);
90
- return null;
69
+ // Build up the yields.
70
+ // TODO: Compare this to a generator or opaque helpers like Children.
71
+ var yields : Array<ReifiedYield> = [];
72
+ var child = unitOfWork.child;
73
+ while (child) {
74
+ recursivelyFillYields(yields, child.output);
75
+ child = child.sibling;
76
}
77
+ var fn = coroutine.handler;
78
+ var props = coroutine.props;
79
+ var nextChildren = fn(props, yields);
80
+
81
+ unitOfWork.stateNode = ReactChildFiber.reconcileChildFibers(
82
+ unitOfWork,
83
+ unitOfWork.stateNode,
84
+ nextChildren
85
+ );
86
+ return unitOfWork.stateNode;
87
}
88
89
exports.completeWork = function(unitOfWork : Fiber) : ?Fiber {
@@ -106,7 +101,12 @@ exports.completeWork = function(unitOfWork : Fiber) : ?Fiber {
101
break;
102
case CoroutineComponent:
103
console.log('/coroutine component', unitOfWork.input.handler.name);
109
- return handleCoroutine(unitOfWork);
104
+ return moveCoroutineToHandlerPhase(unitOfWork);
105
+ case CoroutineHandlerPhase:
106
+ transferOutput(unitOfWork.stateNode, unitOfWork);
107
+ // Reset the tag to now be a first phase coroutine.
108
+ unitOfWork.tag = CoroutineComponent;
109
+ break;
110
case YieldComponent:
111
// Does nothing.
112
break;
src/renderers/shared/fiber/ReactTypesOfWork.js
+2
-1
@@ -18,7 +18,8 @@ var TypesOfWork = {
18
ClassComponent: 2,
19
HostComponent: 3,
20
CoroutineComponent: 4,
21
- YieldComponent: 5,
21
+ CoroutineHandlerPhase: 5,
22
+ YieldComponent: 6,
23
};
24
25
module.exports = TypesOfWork;