Skip to content

Commit 76c17ab

Browse files
authored
Merge pull request #1 from gaearon/fiber-boundaries-refactor
[Fiber] Refactor error boundaries in Fiber
2 parents 0f5d44c + cd10402 commit 76c17ab

File tree

4 files changed

+81
-148
lines changed

4 files changed

+81
-148
lines changed

scripts/fiber/tests-failing.txt

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,9 +87,6 @@ src/renderers/art/__tests__/ReactART-test.js
8787
* resolves refs before componentDidMount
8888
* resolves refs before componentDidUpdate
8989

90-
src/renderers/dom/__tests__/ReactDOMProduction-test.js
91-
* should throw with an error code in production
92-
9390
src/renderers/dom/shared/__tests__/CSSPropertyOperations-test.js
9491
* should set style attribute when styles exist
9592
* should warn when using hyphenated style names

scripts/fiber/tests-passing.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,7 @@ src/renderers/dom/__tests__/ReactDOMProduction-test.js
438438
* should use prod React
439439
* should handle a simple flow
440440
* should call lifecycle methods
441+
* should throw with an error code in production
441442

442443
src/renderers/dom/fiber/__tests__/ReactDOMFiber-test.js
443444
* should render strings as children

src/renderers/shared/fiber/ReactFiberCommitWork.js

Lines changed: 22 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212

1313
'use strict';
1414

15-
import type { TrappedError } from 'ReactFiberScheduler';
1615
import type { Fiber } from 'ReactFiber';
1716
import type { FiberRoot } from 'ReactFiberRoot';
1817
import type { HostConfig } from 'ReactFiberReconciler';
@@ -34,7 +33,7 @@ var {
3433

3534
module.exports = function<T, P, I, TI, C>(
3635
config : HostConfig<T, P, I, TI, C>,
37-
trapError : (boundary : Fiber, error: Error) => TrappedError
36+
trapError : (fiber : Fiber, error: Error, isUnmounting : boolean) => void
3837
) {
3938

4039
const updateContainer = config.updateContainer;
@@ -158,94 +157,71 @@ module.exports = function<T, P, I, TI, C>(
158157
}
159158
}
160159

161-
function commitNestedUnmounts(root : Fiber): Array<TrappedError> | null {
162-
// Since errors are rare, we allocate this array on demand.
163-
let trappedErrors = null;
164-
160+
function commitNestedUnmounts(root : Fiber): void {
165161
// While we're inside a removed host node we don't want to call
166162
// removeChild on the inner nodes because they're removed by the top
167163
// call anyway. We also want to call componentWillUnmount on all
168164
// composites before this host node is removed from the tree. Therefore
169165
// we do an inner loop while we're still inside the host node.
170166
let node : Fiber = root;
171167
while (true) {
172-
const error = commitUnmount(node);
173-
if (error) {
174-
trappedErrors = trappedErrors || [];
175-
trappedErrors.push(error);
176-
}
168+
commitUnmount(node);
177169
if (node.child) {
178170
// TODO: Coroutines need to visit the stateNode.
179171
node = node.child;
180172
continue;
181173
}
182174
if (node === root) {
183-
return trappedErrors;
175+
return;
184176
}
185177
while (!node.sibling) {
186178
if (!node.return || node.return === root) {
187-
return trappedErrors;
179+
return;
188180
}
189181
node = node.return;
190182
}
191183
node = node.sibling;
192184
}
193-
return trappedErrors;
194185
}
195186

196-
function unmountHostComponents(parent, current): Array<TrappedError> | null {
197-
// Since errors are rare, we allocate this array on demand.
198-
let trappedErrors = null;
199-
187+
function unmountHostComponents(parent, current): void {
200188
// We only have the top Fiber that was inserted but we need recurse down its
201189
// children to find all the terminal nodes.
202190
let node : Fiber = current;
203191
while (true) {
204192
if (node.tag === HostComponent || node.tag === HostText) {
205-
const errors = commitNestedUnmounts(node);
206-
if (errors) {
207-
if (!trappedErrors) {
208-
trappedErrors = errors;
209-
} else {
210-
trappedErrors.push.apply(trappedErrors, errors);
211-
}
212-
}
193+
commitNestedUnmounts(node);
213194
// After all the children have unmounted, it is now safe to remove the
214195
// node from the tree.
215196
if (parent) {
216197
removeChild(parent, node.stateNode);
217198
}
218199
} else {
219-
const error = commitUnmount(node);
220-
if (error) {
221-
trappedErrors = trappedErrors || [];
222-
trappedErrors.push(error);
223-
}
200+
commitUnmount(node);
224201
if (node.child) {
225202
// TODO: Coroutines need to visit the stateNode.
226203
node = node.child;
227204
continue;
228205
}
229206
}
230207
if (node === current) {
231-
return trappedErrors;
208+
return;
232209
}
233210
while (!node.sibling) {
234211
if (!node.return || node.return === current) {
235-
return trappedErrors;
212+
return;
236213
}
237214
node = node.return;
238215
}
239216
node = node.sibling;
240217
}
241-
return trappedErrors;
242218
}
243219

244-
function commitDeletion(current : Fiber) : Array<TrappedError> | null {
220+
function commitDeletion(current : Fiber) : void {
245221
// Recursively delete all host nodes from the parent.
246222
const parent = getHostParent(current);
247223
// Detach refs and call componentWillUnmount() on the whole subtree.
248-
const trappedErrors = unmountHostComponents(parent, current);
224+
unmountHostComponents(parent, current);
249225

250226
// Cut off the return pointers to disconnect it from the tree. Ideally, we
251227
// should clear the child pointer of the parent alternate to let this
@@ -258,29 +234,24 @@ module.exports = function<T, P, I, TI, C>(
258234
current.alternate.child = null;
259235
current.alternate.return = null;
260236
}
261-
262-
return trappedErrors;
263237
}
264238

265-
function commitUnmount(current : Fiber) : TrappedError | null {
239+
function commitUnmount(current : Fiber) : void {
266240
switch (current.tag) {
267241
case ClassComponent: {
268242
detachRef(current);
269243
const instance = current.stateNode;
270244
if (typeof instance.componentWillUnmount === 'function') {
271245
const error = tryCallComponentWillUnmount(instance);
272246
if (error) {
273-
return trapError(current, error);
247+
trapError(current, error, true);
274248
}
275249
}
276-
return null;
250+
return;
277251
}
278252
case HostComponent: {
279253
detachRef(current);
280-
return null;
281-
}
282-
default: {
283-
return null;
254+
return;
284255
}
285256
}
286257
}
@@ -325,7 +296,7 @@ module.exports = function<T, P, I, TI, C>(
325296
}
326297
}
327298

328-
function commitLifeCycles(current : ?Fiber, finishedWork : Fiber) : TrappedError | null {
299+
function commitLifeCycles(current : ?Fiber, finishedWork : Fiber) : void {
329300
switch (finishedWork.tag) {
330301
case ClassComponent: {
331302
const instance = finishedWork.stateNode;
@@ -355,9 +326,9 @@ module.exports = function<T, P, I, TI, C>(
355326
}
356327
}
357328
if (error) {
358-
return trapError(finishedWork, error);
329+
trapError(finishedWork, error, false);
359330
}
360-
return null;
331+
return;
361332
}
362333
case HostContainer: {
363334
const rootFiber = finishedWork.stateNode;
@@ -366,15 +337,16 @@ module.exports = function<T, P, I, TI, C>(
366337
rootFiber.callbackList = null;
367338
callCallbacks(callbackList, rootFiber.current.child.stateNode);
368339
}
340+
return;
369341
}
370342
case HostComponent: {
371343
const instance : I = finishedWork.stateNode;
372344
attachRef(current, finishedWork, instance);
373-
return null;
345+
return;
374346
}
375347
case HostText: {
376348
// We have no life-cycles associated with text.
377-
return null;
349+
return;
378350
}
379351
default:
380352
throw new Error('This unit of work tag should not have side-effects.');

0 commit comments

Comments
 (0)