Dependency injection in the begin/complete/commit phases
This just makes them instantiable so that we can get access to the host config in these.
Sebastian Markbage committed
Jun 29, 2016 at 17:24 UTC
a4b8bebe1805c59271cd4dd7e8151a32ba2dff33
4 files changed
+337
-307
src/renderers/shared/fiber/ReactFiberBeginWork.js
+192
-185
@@ -14,6 +14,7 @@
14
15
import type { ReactCoroutine } from 'ReactCoroutine';
16
import type { Fiber } from 'ReactFiber';
17
+import type { HostConfig } from 'ReactFiberReconciler';
18
19
var ReactChildFiber = require('ReactChildFiber');
20
var ReactTypeOfWork = require('ReactTypeOfWork');
@@ -33,211 +34,217 @@ var {
34
} = require('ReactPriorityLevel');
35
var { findNextUnitOfWorkAtPriority } = require('ReactFiberPendingWork');
36
36
-function reconcileChildren(current, workInProgress, nextChildren) {
37
- const priority = workInProgress.pendingWorkPriority;
38
- workInProgress.child = ReactChildFiber.reconcileChildFibers(
39
- workInProgress,
40
- current ? current.child : null,
41
- nextChildren,
42
- priority
43
- );
44
-}
45
-
46
-function updateFunctionalComponent(current, workInProgress) {
47
- var fn = workInProgress.type;
48
- var props = workInProgress.pendingProps;
49
- console.log('update fn:', fn.name);
50
- var nextChildren = fn(props);
51
- reconcileChildren(current, workInProgress, nextChildren);
52
- workInProgress.pendingWorkPriority = NoWork;
53
-}
54
-
55
-function updateHostComponent(current, workInProgress) {
56
- console.log('host component', workInProgress.type, typeof workInProgress.pendingProps.children === 'string' ? workInProgress.pendingProps.children : '');
57
-
58
- var nextChildren = workInProgress.pendingProps.children;
59
-
60
- let priority = workInProgress.pendingWorkPriority;
61
- if (workInProgress.pendingProps.hidden && priority !== OffscreenPriority) {
62
- // If this host component is hidden, we can reconcile its children at
63
- // the lowest priority and bail out from this particular pass. Unless, we're
64
- // currently reconciling the lowest priority.
65
- workInProgress.child = ReactChildFiber.reconcileChildFibers(
66
- workInProgress,
67
- current ? current.child : null,
68
- nextChildren,
69
- OffscreenPriority
70
- );
71
- workInProgress.pendingWorkPriority = OffscreenPriority;
72
- return null;
73
- } else {
37
+module.exports = function<T, P, I>(config : HostConfig<T, P, I>) {
38
+
39
+ function reconcileChildren(current, workInProgress, nextChildren) {
40
+ const priority = workInProgress.pendingWorkPriority;
41
workInProgress.child = ReactChildFiber.reconcileChildFibers(
42
workInProgress,
43
current ? current.child : null,
44
nextChildren,
45
priority
46
);
47
+ }
48
+
49
+ function updateFunctionalComponent(current, workInProgress) {
50
+ var fn = workInProgress.type;
51
+ var props = workInProgress.pendingProps;
52
+ console.log('update fn:', fn.name);
53
+ var nextChildren = fn(props);
54
+ reconcileChildren(current, workInProgress, nextChildren);
55
workInProgress.pendingWorkPriority = NoWork;
81
- return workInProgress.child;
56
}
83
-}
84
-
85
-function mountIndeterminateComponent(current, workInProgress) {
86
- var fn = workInProgress.type;
87
- var props = workInProgress.pendingProps;
88
- var value = fn(props);
89
- if (typeof value === 'object' && value && typeof value.render === 'function') {
90
- console.log('performed work on class:', fn.name);
91
- // Proceed under the assumption that this is a class instance
92
- workInProgress.tag = ClassComponent;
93
- if (workInProgress.alternate) {
94
- workInProgress.alternate.tag = ClassComponent;
95
- }
96
- } else {
97
- console.log('performed work on fn:', fn.name);
98
- // Proceed under the assumption that this is a functional component
99
- workInProgress.tag = FunctionalComponent;
100
- if (workInProgress.alternate) {
101
- workInProgress.alternate.tag = FunctionalComponent;
57
+
58
+ function updateHostComponent(current, workInProgress) {
59
+ console.log('host component', workInProgress.type, typeof workInProgress.pendingProps.children === 'string' ? workInProgress.pendingProps.children : '');
60
+
61
+ var nextChildren = workInProgress.pendingProps.children;
62
+
63
+ let priority = workInProgress.pendingWorkPriority;
64
+ if (workInProgress.pendingProps.hidden && priority !== OffscreenPriority) {
65
+ // If this host component is hidden, we can reconcile its children at
66
+ // the lowest priority and bail out from this particular pass. Unless, we're
67
+ // currently reconciling the lowest priority.
68
+ workInProgress.child = ReactChildFiber.reconcileChildFibers(
69
+ workInProgress,
70
+ current ? current.child : null,
71
+ nextChildren,
72
+ OffscreenPriority
73
+ );
74
+ workInProgress.pendingWorkPriority = OffscreenPriority;
75
+ return null;
76
+ } else {
77
+ workInProgress.child = ReactChildFiber.reconcileChildFibers(
78
+ workInProgress,
79
+ current ? current.child : null,
80
+ nextChildren,
81
+ priority
82
+ );
83
+ workInProgress.pendingWorkPriority = NoWork;
84
+ return workInProgress.child;
85
}
86
}
104
- reconcileChildren(current, workInProgress, value);
105
- workInProgress.pendingWorkPriority = NoWork;
106
-}
107
-
108
-function updateCoroutineComponent(current, workInProgress) {
109
- var coroutine = (workInProgress.pendingProps : ?ReactCoroutine);
110
- if (!coroutine) {
111
- throw new Error('Should be resolved by now');
112
- }
113
- console.log('begin coroutine', workInProgress.type.name);
114
- reconcileChildren(current, workInProgress, coroutine.children);
115
- workInProgress.pendingWorkPriority = NoWork;
116
-}
117
-
118
-function reuseChildren(returnFiber : Fiber, firstChild : Fiber) {
119
- // TODO: None of this should be necessary if structured better.
120
- // The returnFiber pointer only needs to be updated when we walk into this child
121
- // which we don't do right now. If the pending work priority indicated only
122
- // if a child has work rather than if the node has work, then we would know
123
- // by a single lookup on workInProgress rather than having to go through
124
- // each child.
125
- let child = firstChild;
126
- do {
127
- // Update the returnFiber of the child to the newest fiber.
128
- child.return = returnFiber;
129
- // Retain the priority if there's any work left to do in the children.
130
- if (child.pendingWorkPriority !== NoWork &&
131
- (returnFiber.pendingWorkPriority === NoWork ||
132
- returnFiber.pendingWorkPriority > child.pendingWorkPriority)) {
133
- returnFiber.pendingWorkPriority = child.pendingWorkPriority;
134
- }
135
- } while (child = child.sibling);
136
-}
137
-
138
-function beginWork(current : ?Fiber, workInProgress : Fiber) : ?Fiber {
139
- // The current, flushed, state of this fiber is the alternate.
140
- // Ideally nothing should rely on this, but relying on it here
141
- // means that we don't need an additional field on the work in
142
- // progress.
143
- if (current && workInProgress.pendingProps === current.memoizedProps) {
144
- // The most likely scenario is that the previous copy of the tree contains
145
- // the same props as the new one. In that case, we can just copy the output
146
- // and children from that node.
147
- workInProgress.memoizedProps = workInProgress.pendingProps;
148
- workInProgress.output = current.output;
149
- const priorityLevel = workInProgress.pendingWorkPriority;
150
- workInProgress.pendingProps = null;
151
- workInProgress.pendingWorkPriority = NoWork;
152
- workInProgress.stateNode = current.stateNode;
153
- if (current.child) {
154
- // If we bail out but still has work with the current priority in this
155
- // subtree, we need to go find it right now. If we don't, we won't flush
156
- // it until the next tick.
157
- workInProgress.child = current.child;
158
- reuseChildren(workInProgress, workInProgress.child);
159
- if (workInProgress.pendingWorkPriority <= priorityLevel) {
160
- // TODO: This passes the current node and reads the priority level and
161
- // pending props from that. We want it to read our priority level and
162
- // pending props from the work in progress. Needs restructuring.
163
- return findNextUnitOfWorkAtPriority(workInProgress.alternate, priorityLevel);
164
- } else {
165
- return null;
87
+
88
+ function mountIndeterminateComponent(current, workInProgress) {
89
+ var fn = workInProgress.type;
90
+ var props = workInProgress.pendingProps;
91
+ var value = fn(props);
92
+ if (typeof value === 'object' && value && typeof value.render === 'function') {
93
+ console.log('performed work on class:', fn.name);
94
+ // Proceed under the assumption that this is a class instance
95
+ workInProgress.tag = ClassComponent;
96
+ if (workInProgress.alternate) {
97
+ workInProgress.alternate.tag = ClassComponent;
98
}
99
} else {
168
- workInProgress.child = null;
169
- return null;
100
+ console.log('performed work on fn:', fn.name);
101
+ // Proceed under the assumption that this is a functional component
102
+ workInProgress.tag = FunctionalComponent;
103
+ if (workInProgress.alternate) {
104
+ workInProgress.alternate.tag = FunctionalComponent;
105
+ }
106
}
107
+ reconcileChildren(current, workInProgress, value);
108
+ workInProgress.pendingWorkPriority = NoWork;
109
}
110
173
- if (!workInProgress.hasWorkInProgress &&
174
- workInProgress.pendingProps === workInProgress.memoizedProps &&
175
- workInProgress.pendingWorkPriority === NoWork) {
176
- // If we started this work before, and finished it, or if we're in a
177
- // ping-pong update scenario, this version could already be what we're
178
- // looking for. In that case, we should be able to just bail out.
179
- workInProgress.pendingProps = null;
180
- // TODO: We should be able to bail out if there is remaining work at a lower
181
- // priority too. However, I don't know if that is safe or even better since
182
- // the other tree could've potentially finished that work.
183
- return null;
111
+ function updateCoroutineComponent(current, workInProgress) {
112
+ var coroutine = (workInProgress.pendingProps : ?ReactCoroutine);
113
+ if (!coroutine) {
114
+ throw new Error('Should be resolved by now');
115
+ }
116
+ console.log('begin coroutine', workInProgress.type.name);
117
+ reconcileChildren(current, workInProgress, coroutine.children);
118
+ workInProgress.pendingWorkPriority = NoWork;
119
}
120
186
- workInProgress.hasWorkInProgress = true;
187
-
188
- switch (workInProgress.tag) {
189
- case IndeterminateComponent:
190
- mountIndeterminateComponent(current, workInProgress);
191
- return workInProgress.child;
192
- case FunctionalComponent:
193
- updateFunctionalComponent(current, workInProgress);
194
- return workInProgress.child;
195
- case ClassComponent:
196
- console.log('class component', workInProgress.pendingProps.type.name);
197
- return workInProgress.child;
198
- case HostContainer:
199
- reconcileChildren(current, workInProgress, workInProgress.pendingProps);
200
- // A yield component is just a placeholder, we can just run through the
201
- // next one immediately.
202
- workInProgress.pendingWorkPriority = NoWork;
203
- if (workInProgress.child) {
204
- return beginWork(
205
- workInProgress.child.alternate,
206
- workInProgress.child
207
- );
208
- }
209
- return null;
210
- case HostComponent:
211
- return updateHostComponent(current, workInProgress);
212
- case CoroutineHandlerPhase:
213
- // This is a restart. Reset the tag to the initial phase.
214
- workInProgress.tag = CoroutineComponent;
215
- // Intentionally fall through since this is now the same.
216
- case CoroutineComponent:
217
- updateCoroutineComponent(current, workInProgress);
218
- // This doesn't take arbitrary time so we could synchronously just begin
219
- // eagerly do the work of workInProgress.child as an optimization.
220
- if (workInProgress.child) {
221
- return beginWork(
222
- workInProgress.child.alternate,
223
- workInProgress.child
224
- );
121
+ function reuseChildren(returnFiber : Fiber, firstChild : Fiber) {
122
+ // TODO: None of this should be necessary if structured better.
123
+ // The returnFiber pointer only needs to be updated when we walk into this child
124
+ // which we don't do right now. If the pending work priority indicated only
125
+ // if a child has work rather than if the node has work, then we would know
126
+ // by a single lookup on workInProgress rather than having to go through
127
+ // each child.
128
+ let child = firstChild;
129
+ do {
130
+ // Update the returnFiber of the child to the newest fiber.
131
+ child.return = returnFiber;
132
+ // Retain the priority if there's any work left to do in the children.
133
+ if (child.pendingWorkPriority !== NoWork &&
134
+ (returnFiber.pendingWorkPriority === NoWork ||
135
+ returnFiber.pendingWorkPriority > child.pendingWorkPriority)) {
136
+ returnFiber.pendingWorkPriority = child.pendingWorkPriority;
137
}
226
- return workInProgress.child;
227
- case YieldComponent:
228
- // A yield component is just a placeholder, we can just run through the
229
- // next one immediately.
138
+ } while (child = child.sibling);
139
+ }
140
+
141
+ function beginWork(current : ?Fiber, workInProgress : Fiber) : ?Fiber {
142
+ // The current, flushed, state of this fiber is the alternate.
143
+ // Ideally nothing should rely on this, but relying on it here
144
+ // means that we don't need an additional field on the work in
145
+ // progress.
146
+ if (current && workInProgress.pendingProps === current.memoizedProps) {
147
+ // The most likely scenario is that the previous copy of the tree contains
148
+ // the same props as the new one. In that case, we can just copy the output
149
+ // and children from that node.
150
+ workInProgress.memoizedProps = workInProgress.pendingProps;
151
+ workInProgress.output = current.output;
152
+ const priorityLevel = workInProgress.pendingWorkPriority;
153
+ workInProgress.pendingProps = null;
154
workInProgress.pendingWorkPriority = NoWork;
231
- if (workInProgress.sibling) {
232
- return beginWork(
233
- workInProgress.sibling.alternate,
234
- workInProgress.sibling
235
- );
155
+ workInProgress.stateNode = current.stateNode;
156
+ if (current.child) {
157
+ // If we bail out but still has work with the current priority in this
158
+ // subtree, we need to go find it right now. If we don't, we won't flush
159
+ // it until the next tick.
160
+ workInProgress.child = current.child;
161
+ reuseChildren(workInProgress, workInProgress.child);
162
+ if (workInProgress.pendingWorkPriority <= priorityLevel) {
163
+ // TODO: This passes the current node and reads the priority level and
164
+ // pending props from that. We want it to read our priority level and
165
+ // pending props from the work in progress. Needs restructuring.
166
+ return findNextUnitOfWorkAtPriority(workInProgress.alternate, priorityLevel);
167
+ } else {
168
+ return null;
169
+ }
170
+ } else {
171
+ workInProgress.child = null;
172
+ return null;
173
}
174
+ }
175
+
176
+ if (!workInProgress.hasWorkInProgress &&
177
+ workInProgress.pendingProps === workInProgress.memoizedProps &&
178
+ workInProgress.pendingWorkPriority === NoWork) {
179
+ // If we started this work before, and finished it, or if we're in a
180
+ // ping-pong update scenario, this version could already be what we're
181
+ // looking for. In that case, we should be able to just bail out.
182
+ workInProgress.pendingProps = null;
183
+ // TODO: We should be able to bail out if there is remaining work at a lower
184
+ // priority too. However, I don't know if that is safe or even better since
185
+ // the other tree could've potentially finished that work.
186
return null;
238
- default:
239
- throw new Error('Unknown unit of work tag');
187
+ }
188
+
189
+ workInProgress.hasWorkInProgress = true;
190
+
191
+ switch (workInProgress.tag) {
192
+ case IndeterminateComponent:
193
+ mountIndeterminateComponent(current, workInProgress);
194
+ return workInProgress.child;
195
+ case FunctionalComponent:
196
+ updateFunctionalComponent(current, workInProgress);
197
+ return workInProgress.child;
198
+ case ClassComponent:
199
+ console.log('class component', workInProgress.pendingProps.type.name);
200
+ return workInProgress.child;
201
+ case HostContainer:
202
+ reconcileChildren(current, workInProgress, workInProgress.pendingProps);
203
+ // A yield component is just a placeholder, we can just run through the
204
+ // next one immediately.
205
+ workInProgress.pendingWorkPriority = NoWork;
206
+ if (workInProgress.child) {
207
+ return beginWork(
208
+ workInProgress.child.alternate,
209
+ workInProgress.child
210
+ );
211
+ }
212
+ return null;
213
+ case HostComponent:
214
+ return updateHostComponent(current, workInProgress);
215
+ case CoroutineHandlerPhase:
216
+ // This is a restart. Reset the tag to the initial phase.
217
+ workInProgress.tag = CoroutineComponent;
218
+ // Intentionally fall through since this is now the same.
219
+ case CoroutineComponent:
220
+ updateCoroutineComponent(current, workInProgress);
221
+ // This doesn't take arbitrary time so we could synchronously just begin
222
+ // eagerly do the work of workInProgress.child as an optimization.
223
+ if (workInProgress.child) {
224
+ return beginWork(
225
+ workInProgress.child.alternate,
226
+ workInProgress.child
227
+ );
228
+ }
229
+ return workInProgress.child;
230
+ case YieldComponent:
231
+ // A yield component is just a placeholder, we can just run through the
232
+ // next one immediately.
233
+ workInProgress.pendingWorkPriority = NoWork;
234
+ if (workInProgress.sibling) {
235
+ return beginWork(
236
+ workInProgress.sibling.alternate,
237
+ workInProgress.sibling
238
+ );
239
+ }
240
+ return null;
241
+ default:
242
+ throw new Error('Unknown unit of work tag');
243
+ }
244
}
241
-}
245
243
-exports.beginWork = beginWork;
246
+ return {
247
+ beginWork,
248
+ };
249
+
250
+};
src/renderers/shared/fiber/ReactFiberCommitWork.js
+22
-13
@@ -13,6 +13,7 @@
13
'use strict';
14
15
import type { Fiber } from 'ReactFiber';
16
+import type { HostConfig } from 'ReactFiberReconciler';
17
18
var ReactTypeOfWork = require('ReactTypeOfWork');
19
var {
@@ -21,18 +22,26 @@ var {
22
HostComponent,
23
} = ReactTypeOfWork;
24
24
-exports.commitWork = function(finishedWork : Fiber) : void {
25
- switch (finishedWork.tag) {
26
- case ClassComponent:
27
- // TODO: Fire componentDidMount/componentDidUpdate, update refs
28
- return;
29
- case HostContainer:
30
- // TODO: Attach children to root container.
31
- return;
32
- case HostComponent:
33
- console.log('commit updates to host component', finishedWork.type);
34
- return;
35
- default:
36
- throw new Error('This unit of work tag should not have side-effects.');
25
+module.exports = function<T, P, I>(config : HostConfig<T, P, I>) {
26
+
27
+ function commitWork(finishedWork : Fiber) : void {
28
+ switch (finishedWork.tag) {
29
+ case ClassComponent:
30
+ // TODO: Fire componentDidMount/componentDidUpdate, update refs
31
+ return;
32
+ case HostContainer:
33
+ // TODO: Attach children to root container.
34
+ return;
35
+ case HostComponent:
36
+ console.log('commit updates to host component', finishedWork.type);
37
+ return;
38
+ default:
39
+ throw new Error('This unit of work tag should not have side-effects.');
40
+ }
41
}
42
+
43
+ return {
44
+ commitWork,
45
+ };
46
+
47
};
src/renderers/shared/fiber/ReactFiberCompleteWork.js
+115
-106
@@ -14,6 +14,7 @@
14
15
import type { ReactCoroutine } from 'ReactCoroutine';
16
import type { Fiber } from 'ReactFiber';
17
+import type { HostConfig } from 'ReactFiberReconciler';
18
19
import type { ReifiedYield } from 'ReactReifiedYield';
20
@@ -30,117 +31,125 @@ var {
31
YieldComponent,
32
} = ReactTypeOfWork;
33
33
-function markForPostEffect(workInProgress : Fiber) {
34
- // Schedule a side-effect on this fiber, after the children's side-effects.
35
- if (workInProgress.lastEffect) {
36
- workInProgress.lastEffect.nextEffect = workInProgress;
37
- } else {
38
- workInProgress.firstEffect = workInProgress;
34
+module.exports = function<T, P, I>(config : HostConfig<T, P, I>) {
35
+
36
+ function markForPostEffect(workInProgress : Fiber) {
37
+ // Schedule a side-effect on this fiber, after the children's side-effects.
38
+ if (workInProgress.lastEffect) {
39
+ workInProgress.lastEffect.nextEffect = workInProgress;
40
+ } else {
41
+ workInProgress.firstEffect = workInProgress;
42
+ }
43
+ workInProgress.lastEffect = workInProgress;
44
}
40
- workInProgress.lastEffect = workInProgress;
41
-}
42
-
43
-function transferOutput(child : ?Fiber, returnFiber : Fiber) {
44
- // If we have a single result, we just pass that through as the output to
45
- // avoid unnecessary traversal. When we have multiple output, we just pass
46
- // the linked list of fibers that has the individual output values.
47
- returnFiber.output = (child && !child.sibling) ? child.output : child;
48
- returnFiber.memoizedProps = returnFiber.pendingProps;
49
-}
50
-
51
-function recursivelyFillYields(yields, output : ?Fiber | ?ReifiedYield) {
52
- if (!output) {
53
- // Ignore nulls etc.
54
- } else if (output.tag !== undefined) { // TODO: Fix this fragile duck test.
55
- // Detect if this is a fiber, if so it is a fragment result.
56
- // $FlowFixMe: Refinement issue.
57
- var item = (output : Fiber);
58
- do {
59
- recursivelyFillYields(yields, item.output);
60
- item = item.sibling;
61
- } while (item);
62
- } else {
63
- // $FlowFixMe: Refinement issue. If it is not a Fiber or null, it is a yield
64
- yields.push(output);
45
+
46
+ function transferOutput(child : ?Fiber, returnFiber : Fiber) {
47
+ // If we have a single result, we just pass that through as the output to
48
+ // avoid unnecessary traversal. When we have multiple output, we just pass
49
+ // the linked list of fibers that has the individual output values.
50
+ returnFiber.output = (child && !child.sibling) ? child.output : child;
51
+ returnFiber.memoizedProps = returnFiber.pendingProps;
52
}
66
-}
53
68
-function moveCoroutineToHandlerPhase(current : ?Fiber, workInProgress : Fiber) {
69
- var coroutine = (workInProgress.pendingProps : ?ReactCoroutine);
70
- if (!coroutine) {
71
- throw new Error('Should be resolved by now');
54
+ function recursivelyFillYields(yields, output : ?Fiber | ?ReifiedYield) {
55
+ if (!output) {
56
+ // Ignore nulls etc.
57
+ } else if (output.tag !== undefined) { // TODO: Fix this fragile duck test.
58
+ // Detect if this is a fiber, if so it is a fragment result.
59
+ // $FlowFixMe: Refinement issue.
60
+ var item = (output : Fiber);
61
+ do {
62
+ recursivelyFillYields(yields, item.output);
63
+ item = item.sibling;
64
+ } while (item);
65
+ } else {
66
+ // $FlowFixMe: Refinement issue. If it is not a Fiber or null, it is a yield
67
+ yields.push(output);
68
+ }
69
}
70
74
- // First step of the coroutine has completed. Now we need to do the second.
75
- // TODO: It would be nice to have a multi stage coroutine represented by a
76
- // single component, or at least tail call optimize nested ones. Currently
77
- // that requires additional fields that we don't want to add to the fiber.
78
- // So this requires nested handlers.
79
- // Note: This doesn't mutate the alternate node. I don't think it needs to
80
- // since this stage is reset for every pass.
81
- workInProgress.tag = CoroutineHandlerPhase;
82
-
83
- // Build up the yields.
84
- // TODO: Compare this to a generator or opaque helpers like Children.
85
- var yields : Array<ReifiedYield> = [];
86
- var child = workInProgress.child;
87
- while (child) {
88
- recursivelyFillYields(yields, child.output);
89
- child = child.sibling;
71
+ function moveCoroutineToHandlerPhase(current : ?Fiber, workInProgress : Fiber) {
72
+ var coroutine = (workInProgress.pendingProps : ?ReactCoroutine);
73
+ if (!coroutine) {
74
+ throw new Error('Should be resolved by now');
75
+ }
76
+
77
+ // First step of the coroutine has completed. Now we need to do the second.
78
+ // TODO: It would be nice to have a multi stage coroutine represented by a
79
+ // single component, or at least tail call optimize nested ones. Currently
80
+ // that requires additional fields that we don't want to add to the fiber.
81
+ // So this requires nested handlers.
82
+ // Note: This doesn't mutate the alternate node. I don't think it needs to
83
+ // since this stage is reset for every pass.
84
+ workInProgress.tag = CoroutineHandlerPhase;
85
+
86
+ // Build up the yields.
87
+ // TODO: Compare this to a generator or opaque helpers like Children.
88
+ var yields : Array<ReifiedYield> = [];
89
+ var child = workInProgress.child;
90
+ while (child) {
91
+ recursivelyFillYields(yields, child.output);
92
+ child = child.sibling;
93
+ }
94
+ var fn = coroutine.handler;
95
+ var props = coroutine.props;
96
+ var nextChildren = fn(props, yields);
97
+
98
+ var currentFirstChild = current ? current.stateNode : null;
99
+ // Inherit the priority of the returnFiber.
100
+ const priority = workInProgress.pendingWorkPriority;
101
+ workInProgress.stateNode = ReactChildFiber.reconcileChildFibers(
102
+ workInProgress,
103
+ currentFirstChild,
104
+ nextChildren,
105
+ priority
106
+ );
107
+ return workInProgress.stateNode;
108
}
91
- var fn = coroutine.handler;
92
- var props = coroutine.props;
93
- var nextChildren = fn(props, yields);
94
-
95
- var currentFirstChild = current ? current.stateNode : null;
96
- // Inherit the priority of the returnFiber.
97
- const priority = workInProgress.pendingWorkPriority;
98
- workInProgress.stateNode = ReactChildFiber.reconcileChildFibers(
99
- workInProgress,
100
- currentFirstChild,
101
- nextChildren,
102
- priority
103
- );
104
- return workInProgress.stateNode;
105
-}
106
-
107
-exports.completeWork = function(current : ?Fiber, workInProgress : Fiber) : ?Fiber {
108
- switch (workInProgress.tag) {
109
- case FunctionalComponent:
110
- console.log('/functional component', workInProgress.type.name);
111
- transferOutput(workInProgress.child, workInProgress);
112
- return null;
113
- case ClassComponent:
114
- console.log('/class component', workInProgress.type.name);
115
- transferOutput(workInProgress.child, workInProgress);
116
- return null;
117
- case HostContainer:
118
- return null;
119
- case HostComponent:
120
- transferOutput(workInProgress.child, workInProgress);
121
- if (workInProgress.alternate) {
122
- // If we have an alternate, that means this is an update and we need to
123
- // schedule a side-effect to do the updates.
124
- markForPostEffect(workInProgress);
125
- }
126
- console.log('/host component', workInProgress.type);
127
- return null;
128
- case CoroutineComponent:
129
- console.log('/coroutine component', workInProgress.pendingProps.handler.name);
130
- return moveCoroutineToHandlerPhase(current, workInProgress);
131
- case CoroutineHandlerPhase:
132
- transferOutput(workInProgress.stateNode, workInProgress);
133
- // Reset the tag to now be a first phase coroutine.
134
- workInProgress.tag = CoroutineComponent;
135
- return null;
136
- case YieldComponent:
137
- // Does nothing.
138
- return null;
139
-
140
- // Error cases
141
- case IndeterminateComponent:
142
- throw new Error('An indeterminate component should have become determinate before completing.');
143
- default:
144
- throw new Error('Unknown unit of work tag');
109
+
110
+ function completeWork(current : ?Fiber, workInProgress : Fiber) : ?Fiber {
111
+ switch (workInProgress.tag) {
112
+ case FunctionalComponent:
113
+ console.log('/functional component', workInProgress.type.name);
114
+ transferOutput(workInProgress.child, workInProgress);
115
+ return null;
116
+ case ClassComponent:
117
+ console.log('/class component', workInProgress.type.name);
118
+ transferOutput(workInProgress.child, workInProgress);
119
+ return null;
120
+ case HostContainer:
121
+ return null;
122
+ case HostComponent:
123
+ transferOutput(workInProgress.child, workInProgress);
124
+ if (workInProgress.alternate) {
125
+ // If we have an alternate, that means this is an update and we need to
126
+ // schedule a side-effect to do the updates.
127
+ markForPostEffect(workInProgress);
128
+ }
129
+ console.log('/host component', workInProgress.type);
130
+ return null;
131
+ case CoroutineComponent:
132
+ console.log('/coroutine component', workInProgress.pendingProps.handler.name);
133
+ return moveCoroutineToHandlerPhase(current, workInProgress);
134
+ case CoroutineHandlerPhase:
135
+ transferOutput(workInProgress.stateNode, workInProgress);
136
+ // Reset the tag to now be a first phase coroutine.
137
+ workInProgress.tag = CoroutineComponent;
138
+ return null;
139
+ case YieldComponent:
140
+ // Does nothing.
141
+ return null;
142
+
143
+ // Error cases
144
+ case IndeterminateComponent:
145
+ throw new Error('An indeterminate component should have become determinate before completing.');
146
+ default:
147
+ throw new Error('Unknown unit of work tag');
148
+ }
149
}
150
+
151
+ return {
152
+ completeWork,
153
+ };
154
+
155
};
src/renderers/shared/fiber/ReactFiberScheduler.js
+8
-3
@@ -16,10 +16,11 @@ import type { Fiber } from 'ReactFiber';
16
import type { FiberRoot } from 'ReactFiberRoot';
17
import type { HostConfig } from 'ReactFiberReconciler';
18
19
+var ReactFiberBeginWork = require('ReactFiberBeginWork');
20
+var ReactFiberCompleteWork = require('ReactFiberCompleteWork');
21
+var ReactFiberCommitWork = require('ReactFiberCommitWork');
22
+
23
var { cloneFiber } = require('ReactFiber');
20
-var { beginWork } = require('ReactFiberBeginWork');
21
-var { completeWork } = require('ReactFiberCompleteWork');
22
-var { commitWork } = require('ReactFiberCommitWork');
24
var { findNextUnitOfWorkAtPriority } = require('ReactFiberPendingWork');
25
26
var {
@@ -33,6 +34,10 @@ var timeHeuristicForUnitOfWork = 1;
34
35
module.exports = function<T, P, I>(config : HostConfig<T, P, I>) {
36
37
+ const { beginWork } = ReactFiberBeginWork(config);
38
+ const { completeWork } = ReactFiberCompleteWork(config);
39
+ const { commitWork } = ReactFiberCommitWork(config);
40
+
41
// const scheduleHighPriCallback = config.scheduleHighPriCallback;
42
const scheduleLowPriCallback = config.scheduleLowPriCallback;
43