Error recovery should have task priority
This uncovered a separate issue where some errors were being unscheduled and rescheduled multiple times before flushing. Turns out we need to check both a fiber and its alternate when determining if it represents a failed unit of work. I didn't notice this before because we were scheduling a new update on *every* boundary at the end of the commit phase, not just the ones that captured an error during that commit. I updated the unit tests to catch this in the future.
Andrew Clark committed
Dec 3, 2016 at 12:22 UTC
701d128fd1a7731ee8f40e4611c3433e4c258160
7 files changed
+130
-117
src/renderers/shared/fiber/ReactFiberBeginWork.js
+4
@@ -54,6 +54,7 @@ var {
54
var {
55
Placement,
56
ContentReset,
57
+ Err,
58
} = require('ReactTypeOfSideEffect');
59
var ReactCurrentOwner = require('ReactCurrentOwner');
60
var ReactFiberClassComponent = require('ReactFiberClassComponent');
@@ -502,6 +503,9 @@ module.exports = function<T, P, I, TI, C>(
503
throw new Error('Invalid type of work');
504
}
505
506
+ // Add an error effect so we can handle the error during the commit phase
507
+ workInProgress.effectTag |= Err;
508
+
509
if (workInProgress.pendingWorkPriority === NoWork ||
510
workInProgress.pendingWorkPriority > priorityLevel) {
511
return bailoutOnLowPriority(current, workInProgress);
src/renderers/shared/fiber/ReactFiberCommitWork.js
+17
-35
@@ -204,17 +204,15 @@ module.exports = function<T, P, I, TI, C>(
204
}
205
}
206
207
- function commitNestedUnmounts(root : Fiber): boolean {
207
+ function commitNestedUnmounts(root : Fiber): void {
208
// While we're inside a removed host node we don't want to call
209
// removeChild on the inner nodes because they're removed by the top
210
// call anyway. We also want to call componentWillUnmount on all
211
// composites before this host node is removed from the tree. Therefore
212
// we do an inner loop while we're still inside the host node.
213
- let noErrors = true;
213
let node : Fiber = root;
214
while (true) {
216
- const noError = commitUnmount(node);
217
- noErrors = noErrors && noError;
215
+ commitUnmount(node);
216
if (node.child) {
217
// TODO: Coroutines need to visit the stateNode.
218
node.child.return = node;
@@ -222,32 +220,26 @@ module.exports = function<T, P, I, TI, C>(
220
continue;
221
}
222
if (node === root) {
225
- return noErrors;
223
+ return;
224
}
225
while (!node.sibling) {
226
if (!node.return || node.return === root) {
229
- return noErrors;
227
+ return;
228
}
229
node = node.return;
230
}
231
node.sibling.return = node.return;
232
node = node.sibling;
233
}
236
- // This is unreachable but without it Flow complains about implicitly-
237
- // returned undefined.
238
- return noErrors; // eslint-disable-line no-unreachable
234
}
235
241
- // Returns true if it completed without any errors
242
- function unmountHostComponents(parent, current): boolean {
236
+ function unmountHostComponents(parent, current): void {
237
// We only have the top Fiber that was inserted but we need recurse down its
238
// children to find all the terminal nodes.
245
- let noErrors = true;
239
let node : Fiber = current;
240
while (true) {
241
if (node.tag === HostComponent || node.tag === HostText) {
249
- const noError = commitNestedUnmounts(node);
250
- noErrors = noErrors && noError;
242
+ commitNestedUnmounts(node);
243
// After all the children have unmounted, it is now safe to remove the
244
// node from the tree.
245
removeChild(parent, node.stateNode);
@@ -260,8 +252,7 @@ module.exports = function<T, P, I, TI, C>(
252
continue;
253
}
254
} else {
263
- const noError = commitUnmount(node);
264
- noErrors = noErrors && noError;
255
+ commitUnmount(node);
256
if (node.child) {
257
// TODO: Coroutines need to visit the stateNode.
258
node.child.return = node;
@@ -270,11 +261,11 @@ module.exports = function<T, P, I, TI, C>(
261
}
262
}
263
if (node === current) {
273
- return noErrors;
264
+ return;
265
}
266
while (!node.sibling) {
267
if (!node.return || node.return === current) {
277
- return noErrors;
268
+ return;
269
}
270
node = node.return;
271
if (node.tag === HostPortal) {
@@ -286,16 +277,13 @@ module.exports = function<T, P, I, TI, C>(
277
node.sibling.return = node.return;
278
node = node.sibling;
279
}
289
- // This is unreachable but without it Flow complains about implicitly-
290
- // returned undefined.
291
- return noErrors; // eslint-disable-line no-unreachable
280
}
281
294
- function commitDeletion(current : Fiber) : boolean {
282
+ function commitDeletion(current : Fiber) : void {
283
// Recursively delete all host nodes from the parent.
284
const parent = getHostParent(current);
285
// Detach refs and call componentWillUnmount() on the whole subtree.
298
- const noErrors = unmountHostComponents(parent, current);
286
+ unmountHostComponents(parent, current);
287
288
// Cut off the return pointers to disconnect it from the tree. Ideally, we
289
// should clear the child pointer of the parent alternate to let this
@@ -308,12 +296,9 @@ module.exports = function<T, P, I, TI, C>(
296
current.alternate.child = null;
297
current.alternate.return = null;
298
}
311
- return noErrors;
299
}
300
314
- // Returns true if it completed without any errors
315
- function commitUnmount(current : Fiber) : boolean {
316
- let noErrors = true;
301
+ function commitUnmount(current : Fiber) : void {
302
switch (current.tag) {
303
case ClassComponent: {
304
detachRef(current);
@@ -322,27 +307,24 @@ module.exports = function<T, P, I, TI, C>(
307
const error = tryCallComponentWillUnmount(instance);
308
if (error) {
309
captureError(current, error);
325
- noErrors = false;
310
}
311
}
328
- break;
312
+ return;
313
}
314
case HostComponent: {
315
detachRef(current);
332
- break;
316
+ return;
317
}
318
case CoroutineComponent: {
335
- const noError = commitNestedUnmounts(current.stateNode);
336
- noErrors = noErrors && noError;
337
- break;
319
+ commitNestedUnmounts(current.stateNode);
320
+ return;
321
}
322
case HostPortal: {
323
// TODO: this is recursive.
324
commitDeletion(current);
342
- break;
325
+ return;
326
}
327
}
345
- return noErrors;
328
}
329
330
function commitWork(current : ?Fiber, finishedWork : Fiber) : void {
src/renderers/shared/fiber/ReactFiberScheduler.js
+99
-68
@@ -82,6 +82,8 @@ module.exports = function<T, P, I, TI, C>(config : HostConfig<T, P, I, TI, C>) {
82
// Keeps track of whether we're currently in a work loop. Used to batch
83
// nested updates.
84
let isPerformingWork : boolean = false;
85
+ // This lets us know if we should defer a commit until the next frame.
86
+ let isPerformingDeferredWork : boolean = false;
87
88
// The next work in progress fiber that we're currently working on.
89
let nextUnitOfWork : ?Fiber = null;
@@ -100,6 +102,10 @@ module.exports = function<T, P, I, TI, C>(config : HostConfig<T, P, I, TI, C>) {
102
let capturedErrors : Map<Fiber, Error> | null = null;
103
let firstUncaughtError : Error | null = null;
104
105
+ let isCommitting : boolean = false;
106
+ // Error boundaries that captured an error during the current commit.
107
+ let commitPhaseBoundaries : Set<Fiber> | null = null;
108
+
109
let isUnmounting : boolean = false;
110
111
function scheduleAnimationCallback(callback) {
@@ -117,10 +123,6 @@ module.exports = function<T, P, I, TI, C>(config : HostConfig<T, P, I, TI, C>) {
123
}
124
125
function findNextUnitOfWork() {
120
- if (pendingCommit) {
121
- return pendingCommit;
122
- }
123
-
126
// Clear out roots with no more work on them, or if they have uncaught errors
127
while (nextScheduledRoot && nextScheduledRoot.current.pendingWorkPriority === NoWork) {
128
// Unschedule this root.
@@ -140,6 +142,10 @@ module.exports = function<T, P, I, TI, C>(config : HostConfig<T, P, I, TI, C>) {
142
// If there's no work on it, it will get unscheduled too.
143
nextScheduledRoot = next;
144
}
145
+ if (pendingCommit) {
146
+ nextPriorityLevel = pendingCommit.pendingWorkPriority;
147
+ return null;
148
+ }
149
let root = nextScheduledRoot;
150
let highestPriorityRoot = null;
151
let highestPriorityLevel = NoWork;
@@ -167,11 +173,14 @@ module.exports = function<T, P, I, TI, C>(config : HostConfig<T, P, I, TI, C>) {
173
174
// Returns true if the commit phase finishes without any errors.
175
function commitAllWork(finishedWork : Fiber): boolean {
170
- let noErrors = true;
176
+ // We keep track of this so that captureError can collect any boundaries
177
+ // that capture an error during the commit phase. The reason these aren't
178
+ // local to this function is because errors that occur during cWU are
179
+ // captured elsewhere, to prevent the unmount from being interrupted.
180
+ isCommitting = true;
181
182
pendingCommit = null;
183
const root : FiberRoot = (finishedWork.stateNode : any);
174
- resetWorkPriority(finishedWork);
184
if (root.current === finishedWork) {
185
throw new Error(
186
'Cannot commit the same tree as before. This is probably a bug ' +
@@ -180,6 +189,10 @@ module.exports = function<T, P, I, TI, C>(config : HostConfig<T, P, I, TI, C>) {
189
}
190
root.current = finishedWork;
191
192
+ // Updates that occur during the commit phase should have Task priority
193
+ const previousPriorityContext = priorityContext;
194
+ priorityContext = TaskPriority;
195
+
196
prepareForCommit();
197
198
// Commit all the side-effects within a tree.
@@ -229,8 +242,7 @@ module.exports = function<T, P, I, TI, C>(config : HostConfig<T, P, I, TI, C>) {
242
}
243
case Deletion: {
244
isUnmounting = true;
232
- const noError = commitDeletion(effectfulFiber);
233
- noErrors = noErrors && noError;
245
+ commitDeletion(effectfulFiber);
246
isUnmounting = false;
247
break;
248
}
@@ -246,7 +258,6 @@ module.exports = function<T, P, I, TI, C>(config : HostConfig<T, P, I, TI, C>) {
258
commitWork(current, finishedWork);
259
}
260
} catch (error) {
249
- noErrors = false;
261
captureError(effectfulFiber || null, error);
262
if (effectfulFiber) {
263
effectfulFiber = effectfulFiber.nextEffect;
@@ -264,8 +275,6 @@ module.exports = function<T, P, I, TI, C>(config : HostConfig<T, P, I, TI, C>) {
275
// happens as a separate pass so that all effects in the entire tree have
276
// already been invoked.
277
effectfulFiber = finishedWork.firstEffect;
267
- const previousPriorityContext = priorityContext;
268
- priorityContext = TaskPriority;
278
pass2: while (true) {
279
let didHandleRoot = false;
280
try {
@@ -302,7 +311,6 @@ module.exports = function<T, P, I, TI, C>(config : HostConfig<T, P, I, TI, C>) {
311
}
312
}
313
} catch (error) {
305
- noErrors = false;
314
captureError(effectfulFiber || null, error);
315
if (effectfulFiber) {
316
const next = effectfulFiber.nextEffect;
@@ -315,28 +323,26 @@ module.exports = function<T, P, I, TI, C>(config : HostConfig<T, P, I, TI, C>) {
323
break;
324
}
325
318
- if (capturedErrors) {
319
- if (capturedErrors.size) {
320
- capturedErrors.forEach((error, boundary) => {
321
- scheduleUpdate(boundary);
322
- });
323
- } else {
324
- capturedErrors = null;
325
- }
326
+ isCommitting = false;
327
+
328
+ // If we caught any errors during this commit, schedule their boundaries
329
+ // to update.
330
+ let noErrors;
331
+ if (commitPhaseBoundaries) {
332
+ noErrors = false;
333
+ commitPhaseBoundaries.forEach(scheduleUpdate);
334
+ commitPhaseBoundaries = null;
335
+ } else {
336
+ noErrors = true;
337
}
338
339
+ priorityContext = previousPriorityContext;
340
nextUnitOfWork = null;
341
342
return noErrors;
343
}
344
345
function resetWorkPriority(workInProgress : Fiber) {
334
- if (workInProgress.pendingProps) {
335
- // Don't reset the priority if the workInProgress has pending props. This
336
- // could happen if a completed root is updated before it is able to commit.
337
- return;
338
- }
339
-
346
let newPriority = NoWork;
347
// progressedChild is going to be the child set with the highest priority.
348
// Either it is the same as child, or it just bailed out because it choose
@@ -370,11 +376,8 @@ module.exports = function<T, P, I, TI, C>(config : HostConfig<T, P, I, TI, C>) {
376
377
const returnFiber = workInProgress.return;
378
const siblingFiber = workInProgress.sibling;
373
- const isRoot = !returnFiber && !siblingFiber;
379
375
- if (!isRoot) {
376
- resetWorkPriority(workInProgress);
377
- }
380
+ resetWorkPriority(workInProgress);
381
382
if (next) {
383
// If completing this work spawned new work, do that next. We'll come
@@ -382,12 +385,6 @@ module.exports = function<T, P, I, TI, C>(config : HostConfig<T, P, I, TI, C>) {
385
return next;
386
}
387
385
- if (isRoot) {
386
- // If we've reached the root, commit during the next unit of work.
387
- pendingCommit = workInProgress;
388
- return workInProgress;
389
- }
390
-
388
if (returnFiber) {
389
// Append all the effects of the subtree and this fiber onto the effect
390
// list of the parent. The completion order of the children affects the
@@ -426,7 +423,9 @@ module.exports = function<T, P, I, TI, C>(config : HostConfig<T, P, I, TI, C>) {
423
workInProgress = returnFiber;
424
continue;
425
} else {
429
- throw new Error('Should have already handled root.');
426
+ // If we've reached the root, commit during the next unit of work.
427
+ pendingCommit = workInProgress;
428
+ return null;
429
}
430
}
431
}
@@ -476,7 +475,6 @@ module.exports = function<T, P, I, TI, C>(config : HostConfig<T, P, I, TI, C>) {
475
}
476
// See if beginning this work spawns more work.
477
let next = beginFailedWork(current, workInProgress, nextPriorityLevel);
479
- workInProgress.effectTag |= Err;
478
479
if (__DEV__ && ReactFiberInstrumentation.debugTool) {
480
ReactFiberInstrumentation.debugTool.onDidBeginWork(workInProgress);
@@ -517,22 +515,25 @@ module.exports = function<T, P, I, TI, C>(config : HostConfig<T, P, I, TI, C>) {
515
}
516
517
// If there are errors, use a forked version of performUnitOfWork
520
- // TODO: Need to make commitAllWork throw on error before doing this
518
if (capturedErrors && capturedErrors.size) {
519
while (true) {
520
if (!nextUnitOfWork && !pendingCommit) {
521
nextUnitOfWork = findNextUnitOfWork();
522
}
526
- // If we're currently flushing Task work, but the pending commit does
527
- // not have Task priority, don't commit it — we're at the end of a
528
- // deferred work batch and the commit should happen in the next batch.
523
+
524
+ // If we're performing Task work and we're inside a deferred work batch,
525
+ // then we shouldn't commit any work yet. Defer it to the next frame.
526
+ // TODO: Is there a better way check if the pending commit should be
527
+ // deferred? It's not as simple as retaining work priority because
528
+ // the root may receive a lower priority update before the completed
529
+ // work is flushed, causing the new update to be up-prioritized.
530
if (
531
pendingCommit &&
531
- !(priorityLevel === TaskPriority && pendingCommit.pendingWorkPriority !== TaskPriority)
532
+ !(priorityLevel === TaskPriority && isPerformingDeferredWork)
533
) {
534
commitAllWork(pendingCommit);
535
} else if (nextUnitOfWork && nextPriorityLevel !== NoWork && nextPriorityLevel <= priorityLevel) {
535
- if (capturedErrors && capturedErrors.has(nextUnitOfWork)) {
536
+ if (isFailedWork(nextUnitOfWork)) {
537
nextUnitOfWork = performFailedUnitOfWork(nextUnitOfWork);
538
} else {
539
nextUnitOfWork = performUnitOfWork(nextUnitOfWork);
@@ -548,12 +549,16 @@ module.exports = function<T, P, I, TI, C>(config : HostConfig<T, P, I, TI, C>) {
549
if (!nextUnitOfWork && !pendingCommit) {
550
nextUnitOfWork = findNextUnitOfWork();
551
}
551
- // If we're currently flushing Task work, but the pending commit does
552
- // not have Task priority, don't commit it — we're at the end of a
553
- // deferred work batch and the commit should happen in the next batch.
552
+
553
+ // If we're performing Task work and we're inside a deferred work batch,
554
+ // then we shouldn't commit any work yet. Defer it to the next frame.
555
+ // TODO: Is there a better way check if the pending commit should be
556
+ // deferred? It's not as simple as retaining work priority because
557
+ // the root may receive a lower priority update before the completed
558
+ // work is flushed, causing the new update to be up-prioritized.
559
if (
560
pendingCommit &&
556
- !(priorityLevel === TaskPriority && pendingCommit.pendingWorkPriority !== TaskPriority)
561
+ !(priorityLevel === TaskPriority && isPerformingDeferredWork)
562
) {
563
const noError = commitAllWork(pendingCommit);
564
if (!noError) {
@@ -578,7 +583,6 @@ module.exports = function<T, P, I, TI, C>(config : HostConfig<T, P, I, TI, C>) {
583
}
584
585
// If there are errors, use a forked version of performUnitOfWork
581
- // TODO: Need to make commitAllWork throw on error before doing this
586
if (capturedErrors && capturedErrors.size) {
587
while (true) {
588
if (deadline.timeRemaining() > timeHeuristicForUnitOfWork) {
@@ -588,7 +592,7 @@ module.exports = function<T, P, I, TI, C>(config : HostConfig<T, P, I, TI, C>) {
592
if (pendingCommit) {
593
commitAllWork(pendingCommit);
594
} else if (nextUnitOfWork) {
591
- if (capturedErrors && capturedErrors.has(nextUnitOfWork)) {
595
+ if (isFailedWork(nextUnitOfWork)) {
596
nextUnitOfWork = performFailedUnitOfWork(nextUnitOfWork);
597
} else {
598
nextUnitOfWork = performUnitOfWork(nextUnitOfWork);
@@ -633,6 +637,7 @@ module.exports = function<T, P, I, TI, C>(config : HostConfig<T, P, I, TI, C>) {
637
throw new Error('performWork was called recursively.');
638
}
639
isPerformingWork = true;
640
+ isPerformingDeferredWork = priorityLevel >= HighPriority;
641
642
// Perform work until either there's no more work at this priority level, or
643
// (in the case of deferred work) we've run out of time.
@@ -694,13 +699,7 @@ module.exports = function<T, P, I, TI, C>(config : HostConfig<T, P, I, TI, C>) {
699
if (maybeBoundary) {
700
const boundary = maybeBoundary;
701
697
- // Schedule an Task update on the boundary
698
- const previousPriorityContext = priorityContext;
699
- priorityContext = TaskPriority;
700
- scheduleUpdate(boundary);
701
- priorityContext = previousPriorityContext;
702
-
703
- // Complete the boundary as if rendered null.
702
+ // Complete the boundary as if it rendered null.
703
beginFailedWork(boundary.alternate, boundary, priorityLevel);
704
705
// The next unit of work is now the boundary that captured the error.
@@ -724,6 +723,7 @@ module.exports = function<T, P, I, TI, C>(config : HostConfig<T, P, I, TI, C>) {
723
724
// We're done performing work. Time to clean up.
725
isPerformingWork = false;
726
+ isPerformingDeferredWork = false;
727
if (capturedErrors && !capturedErrors.size) {
728
capturedErrors = null;
729
}
@@ -736,6 +736,7 @@ module.exports = function<T, P, I, TI, C>(config : HostConfig<T, P, I, TI, C>) {
736
}
737
}
738
739
+ // Returns the boundary that captured the error, or null if the error is ignored
740
function captureError(failedWork : Fiber | null, error : Error) : Fiber | null {
741
// It is no longer valid because we exited the user code.
742
ReactCurrentOwner.current = null;
@@ -784,11 +785,25 @@ module.exports = function<T, P, I, TI, C>(config : HostConfig<T, P, I, TI, C>) {
785
if (!capturedErrors) {
786
capturedErrors = new Map();
787
}
788
+
789
// Ensure that neither this boundary nor its alternate has captured an
790
// error already.
789
- if (!capturedErrors.has(boundary) &&
790
- !(boundary.alternate && capturedErrors.has(boundary.alternate))) {
791
+ if (!isFailedWork(boundary)) {
792
capturedErrors.set(boundary, error);
793
+ // If we're in the commit phase, defer scheduling an update on the
794
+ // boundary until after the commit is complete
795
+ if (isCommitting) {
796
+ if (!commitPhaseBoundaries) {
797
+ commitPhaseBoundaries = new Set();
798
+ }
799
+ commitPhaseBoundaries.add(boundary);
800
+ } else {
801
+ // Otherwise, schedule an update now. Error recovery has Task priority.
802
+ const previousPriorityContext = priorityContext;
803
+ priorityContext = TaskPriority;
804
+ scheduleUpdate(boundary);
805
+ priorityContext = previousPriorityContext;
806
+ }
807
}
808
return boundary;
809
} else if (!firstUncaughtError) {
@@ -798,27 +813,37 @@ module.exports = function<T, P, I, TI, C>(config : HostConfig<T, P, I, TI, C>) {
813
return null;
814
}
815
816
+ function isFailedWork(fiber : Fiber) : boolean {
817
+ return Boolean(
818
+ capturedErrors &&
819
+ (capturedErrors.has(fiber) || (fiber.alternate && capturedErrors.has(fiber.alternate)))
820
+ );
821
+ }
822
+
823
function commitErrorHandling(effectfulFiber : Fiber) {
824
let error;
825
if (capturedErrors) {
804
- // Get the error associated with the fiber being commited.
826
error = capturedErrors.get(effectfulFiber);
827
capturedErrors.delete(effectfulFiber);
828
+ if (!error) {
829
+ if (effectfulFiber.alternate) {
830
+ effectfulFiber = effectfulFiber.alternate;
831
+ error = capturedErrors.get(effectfulFiber);
832
+ capturedErrors.delete(effectfulFiber);
833
+ }
834
+ }
835
}
836
+
837
if (!error) {
809
- throw new Error('No matching captured error.');
838
+ throw new Error('No error for given unit of work.');
839
}
840
841
switch (effectfulFiber.tag) {
842
case ClassComponent:
843
const instance = effectfulFiber.stateNode;
815
- try {
816
- // Allow the boundary to handle the error, usually by scheduling
817
- // an update to itself
818
- instance.unstable_handleError(error);
819
- } catch (e) {
820
- captureError(effectfulFiber, e);
821
- }
844
+ // Allow the boundary to handle the error, usually by scheduling
845
+ // an update to itself
846
+ instance.unstable_handleError(error);
847
return;
848
case HostRoot:
849
if (!firstUncaughtError) {
@@ -850,6 +875,12 @@ module.exports = function<T, P, I, TI, C>(config : HostConfig<T, P, I, TI, C>) {
875
priorityLevel <= root.current.pendingWorkPriority) {
876
root.current.pendingWorkPriority = priorityLevel;
877
}
878
+ if (root.current.alternate) {
879
+ if (root.current.alternate.pendingWorkPriority === NoWork ||
880
+ priorityLevel <= root.current.alternate.pendingWorkPriority) {
881
+ root.current.alternate.pendingWorkPriority = priorityLevel;
882
+ }
883
+ }
884
885
if (!root.isScheduled) {
886
root.isScheduled = true;
src/renderers/shared/fiber/__tests__/ReactIncrementalErrorHandling-test.js
+1
-5
@@ -88,7 +88,7 @@ describe('ReactIncrementalErrorHandling', () => {
88
expect(ReactNoop.getChildren()).toEqual([]);
89
90
ops.length = 0;
91
- ReactNoop.flushDeferredPri(30 + 5 + 5 + 5 + 5);
91
+ ReactNoop.flushDeferredPri(25 + 10);
92
expect(ops).toEqual([
93
'BrokenRender',
94
'ErrorBoundary unstable_handleError',
@@ -132,10 +132,6 @@ describe('ReactIncrementalErrorHandling', () => {
132
expect(ops).toEqual([
133
'ErrorBoundary render success',
134
'BrokenRender',
135
- ]);
136
- ops = [];
137
- ReactNoop.flushDeferredPri(25 + 5 + 5 + 5);
138
- expect(ops).toEqual([
135
'ErrorBoundary unstable_handleError',
136
'ErrorBoundary render error',
137
]);
src/renderers/shared/fiber/__tests__/ReactIncrementalScheduling-test.js
+2
-2
@@ -483,7 +483,7 @@ describe('ReactIncrementalScheduling', () => {
483
484
ReactNoop.render(<Foo />);
485
486
- ReactNoop.flushDeferredPri(20 + 5 + 5);
486
+ ReactNoop.flushDeferredPri(5 + 20 + 20);
487
expect(ops).toEqual([
488
'render: 0',
489
'componentDidMount (before setState): 0',
@@ -496,7 +496,7 @@ describe('ReactIncrementalScheduling', () => {
496
497
ops = [];
498
instance.setState({ tick: 2 });
499
- ReactNoop.flushDeferredPri(20 + 5 + 5);
499
+ ReactNoop.flushDeferredPri(5 + 20 + 20);
500
501
expect(ops).toEqual([
502
'render: 2',
src/renderers/shared/fiber/__tests__/ReactIncrementalSideEffects-test.js
+1
-1
@@ -491,7 +491,7 @@ describe('ReactIncrementalSideEffects', () => {
491
// To confirm, perform one more unit of work. The tree should now be flushed.
492
// (ReactNoop decrements the time remaining by 5 *before* returning it from
493
// the deadline, so to perform n units of work, you need to give it 5n + 5.
494
- // TODO: This is confusing. Decerement it after.)
494
+ // TODO: This is confusing. Decrement it after.)
495
ReactNoop.flushDeferredPri(10);
496
expect(ReactNoop.getChildren()).toEqual([span(1)]);
497
src/renderers/shared/shared/__tests__/ReactErrorBoundaries-test.js
+6
-6
@@ -808,8 +808,8 @@ describe('ReactErrorBoundaries', () => {
808
...(ReactDOMFeatureFlags.useFiber ? [
809
// In Fiber, noop error boundaries render null
810
'RethrowErrorBoundary componentDidMount',
811
- 'ErrorBoundary componentDidMount',
811
'RethrowErrorBoundary unstable_handleError [!]',
812
+ 'ErrorBoundary componentDidMount',
813
// The error got rethrown here.
814
// This time, the error propagates to the higher boundary
815
'RethrowErrorBoundary componentWillUnmount',
@@ -904,9 +904,9 @@ describe('ReactErrorBoundaries', () => {
904
...(ReactDOMFeatureFlags.useFiber ? [
905
// Finish mounting with null children
906
'BrokenRenderErrorBoundary componentDidMount',
907
- 'ErrorBoundary componentDidMount',
907
// Attempt to handle the error
908
'BrokenRenderErrorBoundary unstable_handleError',
909
+ 'ErrorBoundary componentDidMount',
910
'BrokenRenderErrorBoundary render error [!]',
911
// Boundary fails with new error, propagate to next boundary
912
'BrokenRenderErrorBoundary componentWillUnmount',
@@ -2044,15 +2044,15 @@ describe('ReactErrorBoundaries', () => {
2044
'OuterErrorBoundary componentDidUpdate',
2045
// After the commit phase, attempt to recover from any errors that
2046
// were captured
2047
- 'InnerUnmountBoundary unstable_handleError',
2048
- 'InnerUnmountBoundary componentWillUpdate',
2049
- 'InnerUnmountBoundary render error',
2047
'BrokenComponentDidUpdate componentWillUnmount',
2048
'BrokenComponentDidUpdate componentWillUnmount',
2052
- 'InnerUnmountBoundary componentDidUpdate',
2049
+ 'InnerUnmountBoundary unstable_handleError',
2050
'InnerUpdateBoundary unstable_handleError',
2051
+ 'InnerUnmountBoundary componentWillUpdate',
2052
+ 'InnerUnmountBoundary render error',
2053
'InnerUpdateBoundary componentWillUpdate',
2054
'InnerUpdateBoundary render error',
2055
+ 'InnerUnmountBoundary componentDidUpdate',
2056
'InnerUpdateBoundary componentDidUpdate',
2057
]);
2058