Remove invokeGuardedCallback from commit phase (#21666)
* Remove invokeGuardedCallback from commit phase * Sync fork
Dan Abramov committed
Jun 14, 2021 at 21:45 UTC
a8f5e77b921c890c215fb1c7e24a06f38598deb1
4 files changed
+172
-636
packages/react-dom/src/__tests__/ReactDOM-test.js
-43
@@ -408,49 +408,6 @@ describe('ReactDOM', () => {
408
}
409
});
410
411
- it('throws in DEV if jsdom is destroyed by the time setState() is called', () => {
412
- class App extends React.Component {
413
- state = {x: 1};
414
- componentDidUpdate() {}
415
- render() {
416
- return <div />;
417
- }
418
- }
419
- const container = document.createElement('div');
420
- const instance = ReactDOM.render(<App />, container);
421
- const documentDescriptor = Object.getOwnPropertyDescriptor(
422
- global,
423
- 'document',
424
- );
425
- try {
426
- // Emulate jsdom environment cleanup.
427
- // This is roughly what happens if the test finished and then
428
- // an asynchronous callback tried to setState() after this.
429
- delete global.document;
430
-
431
- // The error we're interested in is thrown by invokeGuardedCallback, which
432
- // in DEV is used 1) to replay a failed begin phase, or 2) when calling
433
- // lifecycle methods. We're triggering the second case here.
434
- const fn = () => instance.setState({x: 2});
435
- if (__DEV__) {
436
- expect(fn).toThrow(
437
- 'The `document` global was defined when React was initialized, but is not ' +
438
- 'defined anymore. This can happen in a test environment if a component ' +
439
- 'schedules an update from an asynchronous callback, but the test has already ' +
440
- 'finished running. To solve this, you can either unmount the component at ' +
441
- 'the end of your test (and ensure that any asynchronous operations get ' +
442
- 'canceled in `componentWillUnmount`), or you can change the test itself ' +
443
- 'to be asynchronous.',
444
- );
445
- } else {
446
- expect(fn).not.toThrow();
447
- }
448
- } finally {
449
- // Don't break other tests.
450
- Object.defineProperty(global, 'document', documentDescriptor);
451
- }
452
- });
453
-
411
it('reports stacks with re-entrant renderToString() calls on the client', () => {
412
function Child2(props) {
413
return <span ariaTypo3="no">{props.children}</span>;
packages/react-reconciler/src/ReactFiberCommitWork.new.js
+86
-264
@@ -57,11 +57,6 @@ import {
57
OffscreenComponent,
58
LegacyHiddenComponent,
59
} from './ReactWorkTags';
60
-import {
61
- invokeGuardedCallback,
62
- hasCaughtError,
63
- clearCaughtError,
64
-} from 'shared/ReactErrorUtils';
60
import {detachDeletedInstance} from './ReactFiberHostConfig';
61
import {
62
NoFlags,
@@ -189,24 +184,10 @@ function safelyCallCommitHookLayoutEffectListMount(
184
current: Fiber,
185
nearestMountedAncestor: Fiber | null,
186
) {
192
- if (__DEV__) {
193
- invokeGuardedCallback(
194
- null,
195
- commitHookEffectListMount,
196
- null,
197
- HookLayout,
198
- current,
199
- );
200
- if (hasCaughtError()) {
201
- const unmountError = clearCaughtError();
202
- captureCommitPhaseError(current, nearestMountedAncestor, unmountError);
203
- }
204
- } else {
205
- try {
206
- commitHookEffectListMount(HookLayout, current);
207
- } catch (unmountError) {
208
- captureCommitPhaseError(current, nearestMountedAncestor, unmountError);
209
- }
187
+ try {
188
+ commitHookEffectListMount(HookLayout, current);
189
+ } catch (unmountError) {
190
+ captureCommitPhaseError(current, nearestMountedAncestor, unmountError);
191
}
192
}
193
@@ -216,24 +197,10 @@ function safelyCallComponentWillUnmount(
197
nearestMountedAncestor: Fiber | null,
198
instance: any,
199
) {
219
- if (__DEV__) {
220
- invokeGuardedCallback(
221
- null,
222
- callComponentWillUnmountWithTimer,
223
- null,
224
- current,
225
- instance,
226
- );
227
- if (hasCaughtError()) {
228
- const unmountError = clearCaughtError();
229
- captureCommitPhaseError(current, nearestMountedAncestor, unmountError);
230
- }
231
- } else {
232
- try {
233
- callComponentWillUnmountWithTimer(current, instance);
234
- } catch (unmountError) {
235
- captureCommitPhaseError(current, nearestMountedAncestor, unmountError);
236
- }
200
+ try {
201
+ callComponentWillUnmountWithTimer(current, instance);
202
+ } catch (unmountError) {
203
+ captureCommitPhaseError(current, nearestMountedAncestor, unmountError);
204
}
205
}
206
@@ -243,35 +210,19 @@ function safelyCallComponentDidMount(
210
nearestMountedAncestor: Fiber | null,
211
instance: any,
212
) {
246
- if (__DEV__) {
247
- invokeGuardedCallback(null, instance.componentDidMount, instance);
248
- if (hasCaughtError()) {
249
- const unmountError = clearCaughtError();
250
- captureCommitPhaseError(current, nearestMountedAncestor, unmountError);
251
- }
252
- } else {
253
- try {
254
- instance.componentDidMount();
255
- } catch (unmountError) {
256
- captureCommitPhaseError(current, nearestMountedAncestor, unmountError);
257
- }
213
+ try {
214
+ instance.componentDidMount();
215
+ } catch (unmountError) {
216
+ captureCommitPhaseError(current, nearestMountedAncestor, unmountError);
217
}
218
}
219
220
// Capture errors so they don't interrupt mounting.
221
function safelyAttachRef(current: Fiber, nearestMountedAncestor: Fiber | null) {
263
- if (__DEV__) {
264
- invokeGuardedCallback(null, commitAttachRef, null, current);
265
- if (hasCaughtError()) {
266
- const unmountError = clearCaughtError();
267
- captureCommitPhaseError(current, nearestMountedAncestor, unmountError);
268
- }
269
- } else {
270
- try {
271
- commitAttachRef(current);
272
- } catch (unmountError) {
273
- captureCommitPhaseError(current, nearestMountedAncestor, unmountError);
274
- }
222
+ try {
223
+ commitAttachRef(current);
224
+ } catch (unmountError) {
225
+ captureCommitPhaseError(current, nearestMountedAncestor, unmountError);
226
}
227
}
228
@@ -279,42 +230,23 @@ function safelyDetachRef(current: Fiber, nearestMountedAncestor: Fiber | null) {
230
const ref = current.ref;
231
if (ref !== null) {
232
if (typeof ref === 'function') {
282
- if (__DEV__) {
233
+ try {
234
if (
235
enableProfilerTimer &&
236
enableProfilerCommitHooks &&
237
current.mode & ProfileMode
238
) {
288
- startLayoutEffectTimer();
289
- invokeGuardedCallback(null, ref, null, null);
290
- recordLayoutEffectDuration(current);
291
- } else {
292
- invokeGuardedCallback(null, ref, null, null);
293
- }
294
-
295
- if (hasCaughtError()) {
296
- const refError = clearCaughtError();
297
- captureCommitPhaseError(current, nearestMountedAncestor, refError);
298
- }
299
- } else {
300
- try {
301
- if (
302
- enableProfilerTimer &&
303
- enableProfilerCommitHooks &&
304
- current.mode & ProfileMode
305
- ) {
306
- try {
307
- startLayoutEffectTimer();
308
- ref(null);
309
- } finally {
310
- recordLayoutEffectDuration(current);
311
- }
312
- } else {
239
+ try {
240
+ startLayoutEffectTimer();
241
ref(null);
242
+ } finally {
243
+ recordLayoutEffectDuration(current);
244
}
315
- } catch (refError) {
316
- captureCommitPhaseError(current, nearestMountedAncestor, refError);
245
+ } else {
246
+ ref(null);
247
}
248
+ } catch (error) {
249
+ captureCommitPhaseError(current, nearestMountedAncestor, error);
250
}
251
} else {
252
ref.current = null;
@@ -327,18 +259,10 @@ function safelyCallDestroy(
259
nearestMountedAncestor: Fiber | null,
260
destroy: () => void,
261
) {
330
- if (__DEV__) {
331
- invokeGuardedCallback(null, destroy, null);
332
- if (hasCaughtError()) {
333
- const error = clearCaughtError();
334
- captureCommitPhaseError(current, nearestMountedAncestor, error);
335
- }
336
- } else {
337
- try {
338
- destroy();
339
- } catch (error) {
340
- captureCommitPhaseError(current, nearestMountedAncestor, error);
341
- }
262
+ try {
263
+ destroy();
264
+ } catch (error) {
265
+ captureCommitPhaseError(current, nearestMountedAncestor, error);
266
}
267
}
268
@@ -395,26 +319,13 @@ function commitBeforeMutationEffects_begin() {
319
function commitBeforeMutationEffects_complete() {
320
while (nextEffect !== null) {
321
const fiber = nextEffect;
398
- if (__DEV__) {
399
- setCurrentDebugFiberInDEV(fiber);
400
- invokeGuardedCallback(
401
- null,
402
- commitBeforeMutationEffectsOnFiber,
403
- null,
404
- fiber,
405
- );
406
- if (hasCaughtError()) {
407
- const error = clearCaughtError();
408
- captureCommitPhaseError(fiber, fiber.return, error);
409
- }
410
- resetCurrentDebugFiberInDEV();
411
- } else {
412
- try {
413
- commitBeforeMutationEffectsOnFiber(fiber);
414
- } catch (error) {
415
- captureCommitPhaseError(fiber, fiber.return, error);
416
- }
322
+ setCurrentDebugFiberInDEV(fiber);
323
+ try {
324
+ commitBeforeMutationEffectsOnFiber(fiber);
325
+ } catch (error) {
326
+ captureCommitPhaseError(fiber, fiber.return, error);
327
}
328
+ resetCurrentDebugFiberInDEV();
329
330
const sibling = fiber.sibling;
331
if (sibling !== null) {
@@ -2151,25 +2062,10 @@ function commitMutationEffects_begin(root: FiberRoot) {
2062
if (deletions !== null) {
2063
for (let i = 0; i < deletions.length; i++) {
2064
const childToDelete = deletions[i];
2154
- if (__DEV__) {
2155
- invokeGuardedCallback(
2156
- null,
2157
- commitDeletion,
2158
- null,
2159
- root,
2160
- childToDelete,
2161
- fiber,
2162
- );
2163
- if (hasCaughtError()) {
2164
- const error = clearCaughtError();
2165
- captureCommitPhaseError(childToDelete, fiber, error);
2166
- }
2167
- } else {
2168
- try {
2169
- commitDeletion(root, childToDelete, fiber);
2170
- } catch (error) {
2171
- captureCommitPhaseError(childToDelete, fiber, error);
2172
- }
2065
+ try {
2066
+ commitDeletion(root, childToDelete, fiber);
2067
+ } catch (error) {
2068
+ captureCommitPhaseError(childToDelete, fiber, error);
2069
}
2070
}
2071
}
@@ -2187,27 +2083,13 @@ function commitMutationEffects_begin(root: FiberRoot) {
2083
function commitMutationEffects_complete(root: FiberRoot) {
2084
while (nextEffect !== null) {
2085
const fiber = nextEffect;
2190
- if (__DEV__) {
2191
- setCurrentDebugFiberInDEV(fiber);
2192
- invokeGuardedCallback(
2193
- null,
2194
- commitMutationEffectsOnFiber,
2195
- null,
2196
- fiber,
2197
- root,
2198
- );
2199
- if (hasCaughtError()) {
2200
- const error = clearCaughtError();
2201
- captureCommitPhaseError(fiber, fiber.return, error);
2202
- }
2203
- resetCurrentDebugFiberInDEV();
2204
- } else {
2205
- try {
2206
- commitMutationEffectsOnFiber(fiber, root);
2207
- } catch (error) {
2208
- captureCommitPhaseError(fiber, fiber.return, error);
2209
- }
2086
+ setCurrentDebugFiberInDEV(fiber);
2087
+ try {
2088
+ commitMutationEffectsOnFiber(fiber, root);
2089
+ } catch (error) {
2090
+ captureCommitPhaseError(fiber, fiber.return, error);
2091
}
2092
+ resetCurrentDebugFiberInDEV();
2093
2094
const sibling = fiber.sibling;
2095
if (sibling !== null) {
@@ -2444,29 +2326,13 @@ function commitLayoutMountEffects_complete(
2326
}
2327
} else if ((fiber.flags & LayoutMask) !== NoFlags) {
2328
const current = fiber.alternate;
2447
- if (__DEV__) {
2448
- setCurrentDebugFiberInDEV(fiber);
2449
- invokeGuardedCallback(
2450
- null,
2451
- commitLayoutEffectOnFiber,
2452
- null,
2453
- root,
2454
- current,
2455
- fiber,
2456
- committedLanes,
2457
- );
2458
- if (hasCaughtError()) {
2459
- const error = clearCaughtError();
2460
- captureCommitPhaseError(fiber, fiber.return, error);
2461
- }
2462
- resetCurrentDebugFiberInDEV();
2463
- } else {
2464
- try {
2465
- commitLayoutEffectOnFiber(root, current, fiber, committedLanes);
2466
- } catch (error) {
2467
- captureCommitPhaseError(fiber, fiber.return, error);
2468
- }
2329
+ setCurrentDebugFiberInDEV(fiber);
2330
+ try {
2331
+ commitLayoutEffectOnFiber(root, current, fiber, committedLanes);
2332
+ } catch (error) {
2333
+ captureCommitPhaseError(fiber, fiber.return, error);
2334
}
2335
+ resetCurrentDebugFiberInDEV();
2336
}
2337
2338
if (fiber === subtreeRoot) {
@@ -2513,27 +2379,13 @@ function commitPassiveMountEffects_complete(
2379
while (nextEffect !== null) {
2380
const fiber = nextEffect;
2381
if ((fiber.flags & Passive) !== NoFlags) {
2516
- if (__DEV__) {
2517
- setCurrentDebugFiberInDEV(fiber);
2518
- invokeGuardedCallback(
2519
- null,
2520
- commitPassiveMountOnFiber,
2521
- null,
2522
- root,
2523
- fiber,
2524
- );
2525
- if (hasCaughtError()) {
2526
- const error = clearCaughtError();
2527
- captureCommitPhaseError(fiber, fiber.return, error);
2528
- }
2529
- resetCurrentDebugFiberInDEV();
2530
- } else {
2531
- try {
2532
- commitPassiveMountOnFiber(root, fiber);
2533
- } catch (error) {
2534
- captureCommitPhaseError(fiber, fiber.return, error);
2535
- }
2382
+ setCurrentDebugFiberInDEV(fiber);
2383
+ try {
2384
+ commitPassiveMountOnFiber(root, fiber);
2385
+ } catch (error) {
2386
+ captureCommitPhaseError(fiber, fiber.return, error);
2387
}
2388
+ resetCurrentDebugFiberInDEV();
2389
}
2390
2391
if (fiber === subtreeRoot) {
@@ -2810,25 +2662,19 @@ function invokeLayoutEffectMountInDEV(fiber: Fiber): void {
2662
case FunctionComponent:
2663
case ForwardRef:
2664
case SimpleMemoComponent: {
2813
- invokeGuardedCallback(
2814
- null,
2815
- commitHookEffectListMount,
2816
- null,
2817
- HookLayout | HookHasEffect,
2818
- fiber,
2819
- );
2820
- if (hasCaughtError()) {
2821
- const mountError = clearCaughtError();
2822
- captureCommitPhaseError(fiber, fiber.return, mountError);
2665
+ try {
2666
+ commitHookEffectListMount(HookLayout | HookHasEffect, fiber);
2667
+ } catch (error) {
2668
+ captureCommitPhaseError(fiber, fiber.return, error);
2669
}
2670
break;
2671
}
2672
case ClassComponent: {
2673
const instance = fiber.stateNode;
2828
- invokeGuardedCallback(null, instance.componentDidMount, instance);
2829
- if (hasCaughtError()) {
2830
- const mountError = clearCaughtError();
2831
- captureCommitPhaseError(fiber, fiber.return, mountError);
2674
+ try {
2675
+ instance.componentDidMount();
2676
+ } catch (error) {
2677
+ captureCommitPhaseError(fiber, fiber.return, error);
2678
}
2679
break;
2680
}
@@ -2844,16 +2690,10 @@ function invokePassiveEffectMountInDEV(fiber: Fiber): void {
2690
case FunctionComponent:
2691
case ForwardRef:
2692
case SimpleMemoComponent: {
2847
- invokeGuardedCallback(
2848
- null,
2849
- commitHookEffectListMount,
2850
- null,
2851
- HookPassive | HookHasEffect,
2852
- fiber,
2853
- );
2854
- if (hasCaughtError()) {
2855
- const mountError = clearCaughtError();
2856
- captureCommitPhaseError(fiber, fiber.return, mountError);
2693
+ try {
2694
+ commitHookEffectListMount(HookPassive | HookHasEffect, fiber);
2695
+ } catch (error) {
2696
+ captureCommitPhaseError(fiber, fiber.return, error);
2697
}
2698
break;
2699
}
@@ -2869,35 +2709,21 @@ function invokeLayoutEffectUnmountInDEV(fiber: Fiber): void {
2709
case FunctionComponent:
2710
case ForwardRef:
2711
case SimpleMemoComponent: {
2872
- invokeGuardedCallback(
2873
- null,
2874
- commitHookEffectListUnmount,
2875
- null,
2876
- HookLayout | HookHasEffect,
2877
- fiber,
2878
- fiber.return,
2879
- );
2880
- if (hasCaughtError()) {
2881
- const unmountError = clearCaughtError();
2882
- captureCommitPhaseError(fiber, fiber.return, unmountError);
2712
+ try {
2713
+ commitHookEffectListUnmount(
2714
+ HookLayout | HookHasEffect,
2715
+ fiber,
2716
+ fiber.return,
2717
+ );
2718
+ } catch (error) {
2719
+ captureCommitPhaseError(fiber, fiber.return, error);
2720
}
2721
break;
2722
}
2723
case ClassComponent: {
2724
const instance = fiber.stateNode;
2725
if (typeof instance.componentWillUnmount === 'function') {
2889
- invokeGuardedCallback(
2890
- null,
2891
- safelyCallComponentWillUnmount,
2892
- null,
2893
- fiber,
2894
- fiber.return,
2895
- instance,
2896
- );
2897
- if (hasCaughtError()) {
2898
- const unmountError = clearCaughtError();
2899
- captureCommitPhaseError(fiber, fiber.return, unmountError);
2900
- }
2726
+ safelyCallComponentWillUnmount(fiber, fiber.return, instance);
2727
}
2728
break;
2729
}
@@ -2913,19 +2739,15 @@ function invokePassiveEffectUnmountInDEV(fiber: Fiber): void {
2739
case FunctionComponent:
2740
case ForwardRef:
2741
case SimpleMemoComponent: {
2916
- invokeGuardedCallback(
2917
- null,
2918
- commitHookEffectListUnmount,
2919
- null,
2920
- HookPassive | HookHasEffect,
2921
- fiber,
2922
- fiber.return,
2923
- );
2924
- if (hasCaughtError()) {
2925
- const unmountError = clearCaughtError();
2926
- captureCommitPhaseError(fiber, fiber.return, unmountError);
2742
+ try {
2743
+ commitHookEffectListUnmount(
2744
+ HookPassive | HookHasEffect,
2745
+ fiber,
2746
+ fiber.return,
2747
+ );
2748
+ } catch (error) {
2749
+ captureCommitPhaseError(fiber, fiber.return, error);
2750
}
2928
- break;
2751
}
2752
}
2753
}
packages/react-reconciler/src/ReactFiberCommitWork.old.js
+86
-264
@@ -57,11 +57,6 @@ import {
57
OffscreenComponent,
58
LegacyHiddenComponent,
59
} from './ReactWorkTags';
60
-import {
61
- invokeGuardedCallback,
62
- hasCaughtError,
63
- clearCaughtError,
64
-} from 'shared/ReactErrorUtils';
60
import {detachDeletedInstance} from './ReactFiberHostConfig';
61
import {
62
NoFlags,
@@ -189,24 +184,10 @@ function safelyCallCommitHookLayoutEffectListMount(
184
current: Fiber,
185
nearestMountedAncestor: Fiber | null,
186
) {
192
- if (__DEV__) {
193
- invokeGuardedCallback(
194
- null,
195
- commitHookEffectListMount,
196
- null,
197
- HookLayout,
198
- current,
199
- );
200
- if (hasCaughtError()) {
201
- const unmountError = clearCaughtError();
202
- captureCommitPhaseError(current, nearestMountedAncestor, unmountError);
203
- }
204
- } else {
205
- try {
206
- commitHookEffectListMount(HookLayout, current);
207
- } catch (unmountError) {
208
- captureCommitPhaseError(current, nearestMountedAncestor, unmountError);
209
- }
187
+ try {
188
+ commitHookEffectListMount(HookLayout, current);
189
+ } catch (unmountError) {
190
+ captureCommitPhaseError(current, nearestMountedAncestor, unmountError);
191
}
192
}
193
@@ -216,24 +197,10 @@ function safelyCallComponentWillUnmount(
197
nearestMountedAncestor: Fiber | null,
198
instance: any,
199
) {
219
- if (__DEV__) {
220
- invokeGuardedCallback(
221
- null,
222
- callComponentWillUnmountWithTimer,
223
- null,
224
- current,
225
- instance,
226
- );
227
- if (hasCaughtError()) {
228
- const unmountError = clearCaughtError();
229
- captureCommitPhaseError(current, nearestMountedAncestor, unmountError);
230
- }
231
- } else {
232
- try {
233
- callComponentWillUnmountWithTimer(current, instance);
234
- } catch (unmountError) {
235
- captureCommitPhaseError(current, nearestMountedAncestor, unmountError);
236
- }
200
+ try {
201
+ callComponentWillUnmountWithTimer(current, instance);
202
+ } catch (unmountError) {
203
+ captureCommitPhaseError(current, nearestMountedAncestor, unmountError);
204
}
205
}
206
@@ -243,35 +210,19 @@ function safelyCallComponentDidMount(
210
nearestMountedAncestor: Fiber | null,
211
instance: any,
212
) {
246
- if (__DEV__) {
247
- invokeGuardedCallback(null, instance.componentDidMount, instance);
248
- if (hasCaughtError()) {
249
- const unmountError = clearCaughtError();
250
- captureCommitPhaseError(current, nearestMountedAncestor, unmountError);
251
- }
252
- } else {
253
- try {
254
- instance.componentDidMount();
255
- } catch (unmountError) {
256
- captureCommitPhaseError(current, nearestMountedAncestor, unmountError);
257
- }
213
+ try {
214
+ instance.componentDidMount();
215
+ } catch (unmountError) {
216
+ captureCommitPhaseError(current, nearestMountedAncestor, unmountError);
217
}
218
}
219
220
// Capture errors so they don't interrupt mounting.
221
function safelyAttachRef(current: Fiber, nearestMountedAncestor: Fiber | null) {
263
- if (__DEV__) {
264
- invokeGuardedCallback(null, commitAttachRef, null, current);
265
- if (hasCaughtError()) {
266
- const unmountError = clearCaughtError();
267
- captureCommitPhaseError(current, nearestMountedAncestor, unmountError);
268
- }
269
- } else {
270
- try {
271
- commitAttachRef(current);
272
- } catch (unmountError) {
273
- captureCommitPhaseError(current, nearestMountedAncestor, unmountError);
274
- }
222
+ try {
223
+ commitAttachRef(current);
224
+ } catch (unmountError) {
225
+ captureCommitPhaseError(current, nearestMountedAncestor, unmountError);
226
}
227
}
228
@@ -279,42 +230,23 @@ function safelyDetachRef(current: Fiber, nearestMountedAncestor: Fiber | null) {
230
const ref = current.ref;
231
if (ref !== null) {
232
if (typeof ref === 'function') {
282
- if (__DEV__) {
233
+ try {
234
if (
235
enableProfilerTimer &&
236
enableProfilerCommitHooks &&
237
current.mode & ProfileMode
238
) {
288
- startLayoutEffectTimer();
289
- invokeGuardedCallback(null, ref, null, null);
290
- recordLayoutEffectDuration(current);
291
- } else {
292
- invokeGuardedCallback(null, ref, null, null);
293
- }
294
-
295
- if (hasCaughtError()) {
296
- const refError = clearCaughtError();
297
- captureCommitPhaseError(current, nearestMountedAncestor, refError);
298
- }
299
- } else {
300
- try {
301
- if (
302
- enableProfilerTimer &&
303
- enableProfilerCommitHooks &&
304
- current.mode & ProfileMode
305
- ) {
306
- try {
307
- startLayoutEffectTimer();
308
- ref(null);
309
- } finally {
310
- recordLayoutEffectDuration(current);
311
- }
312
- } else {
239
+ try {
240
+ startLayoutEffectTimer();
241
ref(null);
242
+ } finally {
243
+ recordLayoutEffectDuration(current);
244
}
315
- } catch (refError) {
316
- captureCommitPhaseError(current, nearestMountedAncestor, refError);
245
+ } else {
246
+ ref(null);
247
}
248
+ } catch (error) {
249
+ captureCommitPhaseError(current, nearestMountedAncestor, error);
250
}
251
} else {
252
ref.current = null;
@@ -327,18 +259,10 @@ function safelyCallDestroy(
259
nearestMountedAncestor: Fiber | null,
260
destroy: () => void,
261
) {
330
- if (__DEV__) {
331
- invokeGuardedCallback(null, destroy, null);
332
- if (hasCaughtError()) {
333
- const error = clearCaughtError();
334
- captureCommitPhaseError(current, nearestMountedAncestor, error);
335
- }
336
- } else {
337
- try {
338
- destroy();
339
- } catch (error) {
340
- captureCommitPhaseError(current, nearestMountedAncestor, error);
341
- }
262
+ try {
263
+ destroy();
264
+ } catch (error) {
265
+ captureCommitPhaseError(current, nearestMountedAncestor, error);
266
}
267
}
268
@@ -395,26 +319,13 @@ function commitBeforeMutationEffects_begin() {
319
function commitBeforeMutationEffects_complete() {
320
while (nextEffect !== null) {
321
const fiber = nextEffect;
398
- if (__DEV__) {
399
- setCurrentDebugFiberInDEV(fiber);
400
- invokeGuardedCallback(
401
- null,
402
- commitBeforeMutationEffectsOnFiber,
403
- null,
404
- fiber,
405
- );
406
- if (hasCaughtError()) {
407
- const error = clearCaughtError();
408
- captureCommitPhaseError(fiber, fiber.return, error);
409
- }
410
- resetCurrentDebugFiberInDEV();
411
- } else {
412
- try {
413
- commitBeforeMutationEffectsOnFiber(fiber);
414
- } catch (error) {
415
- captureCommitPhaseError(fiber, fiber.return, error);
416
- }
322
+ setCurrentDebugFiberInDEV(fiber);
323
+ try {
324
+ commitBeforeMutationEffectsOnFiber(fiber);
325
+ } catch (error) {
326
+ captureCommitPhaseError(fiber, fiber.return, error);
327
}
328
+ resetCurrentDebugFiberInDEV();
329
330
const sibling = fiber.sibling;
331
if (sibling !== null) {
@@ -2151,25 +2062,10 @@ function commitMutationEffects_begin(root: FiberRoot) {
2062
if (deletions !== null) {
2063
for (let i = 0; i < deletions.length; i++) {
2064
const childToDelete = deletions[i];
2154
- if (__DEV__) {
2155
- invokeGuardedCallback(
2156
- null,
2157
- commitDeletion,
2158
- null,
2159
- root,
2160
- childToDelete,
2161
- fiber,
2162
- );
2163
- if (hasCaughtError()) {
2164
- const error = clearCaughtError();
2165
- captureCommitPhaseError(childToDelete, fiber, error);
2166
- }
2167
- } else {
2168
- try {
2169
- commitDeletion(root, childToDelete, fiber);
2170
- } catch (error) {
2171
- captureCommitPhaseError(childToDelete, fiber, error);
2172
- }
2065
+ try {
2066
+ commitDeletion(root, childToDelete, fiber);
2067
+ } catch (error) {
2068
+ captureCommitPhaseError(childToDelete, fiber, error);
2069
}
2070
}
2071
}
@@ -2187,27 +2083,13 @@ function commitMutationEffects_begin(root: FiberRoot) {
2083
function commitMutationEffects_complete(root: FiberRoot) {
2084
while (nextEffect !== null) {
2085
const fiber = nextEffect;
2190
- if (__DEV__) {
2191
- setCurrentDebugFiberInDEV(fiber);
2192
- invokeGuardedCallback(
2193
- null,
2194
- commitMutationEffectsOnFiber,
2195
- null,
2196
- fiber,
2197
- root,
2198
- );
2199
- if (hasCaughtError()) {
2200
- const error = clearCaughtError();
2201
- captureCommitPhaseError(fiber, fiber.return, error);
2202
- }
2203
- resetCurrentDebugFiberInDEV();
2204
- } else {
2205
- try {
2206
- commitMutationEffectsOnFiber(fiber, root);
2207
- } catch (error) {
2208
- captureCommitPhaseError(fiber, fiber.return, error);
2209
- }
2086
+ setCurrentDebugFiberInDEV(fiber);
2087
+ try {
2088
+ commitMutationEffectsOnFiber(fiber, root);
2089
+ } catch (error) {
2090
+ captureCommitPhaseError(fiber, fiber.return, error);
2091
}
2092
+ resetCurrentDebugFiberInDEV();
2093
2094
const sibling = fiber.sibling;
2095
if (sibling !== null) {
@@ -2444,29 +2326,13 @@ function commitLayoutMountEffects_complete(
2326
}
2327
} else if ((fiber.flags & LayoutMask) !== NoFlags) {
2328
const current = fiber.alternate;
2447
- if (__DEV__) {
2448
- setCurrentDebugFiberInDEV(fiber);
2449
- invokeGuardedCallback(
2450
- null,
2451
- commitLayoutEffectOnFiber,
2452
- null,
2453
- root,
2454
- current,
2455
- fiber,
2456
- committedLanes,
2457
- );
2458
- if (hasCaughtError()) {
2459
- const error = clearCaughtError();
2460
- captureCommitPhaseError(fiber, fiber.return, error);
2461
- }
2462
- resetCurrentDebugFiberInDEV();
2463
- } else {
2464
- try {
2465
- commitLayoutEffectOnFiber(root, current, fiber, committedLanes);
2466
- } catch (error) {
2467
- captureCommitPhaseError(fiber, fiber.return, error);
2468
- }
2329
+ setCurrentDebugFiberInDEV(fiber);
2330
+ try {
2331
+ commitLayoutEffectOnFiber(root, current, fiber, committedLanes);
2332
+ } catch (error) {
2333
+ captureCommitPhaseError(fiber, fiber.return, error);
2334
}
2335
+ resetCurrentDebugFiberInDEV();
2336
}
2337
2338
if (fiber === subtreeRoot) {
@@ -2513,27 +2379,13 @@ function commitPassiveMountEffects_complete(
2379
while (nextEffect !== null) {
2380
const fiber = nextEffect;
2381
if ((fiber.flags & Passive) !== NoFlags) {
2516
- if (__DEV__) {
2517
- setCurrentDebugFiberInDEV(fiber);
2518
- invokeGuardedCallback(
2519
- null,
2520
- commitPassiveMountOnFiber,
2521
- null,
2522
- root,
2523
- fiber,
2524
- );
2525
- if (hasCaughtError()) {
2526
- const error = clearCaughtError();
2527
- captureCommitPhaseError(fiber, fiber.return, error);
2528
- }
2529
- resetCurrentDebugFiberInDEV();
2530
- } else {
2531
- try {
2532
- commitPassiveMountOnFiber(root, fiber);
2533
- } catch (error) {
2534
- captureCommitPhaseError(fiber, fiber.return, error);
2535
- }
2382
+ setCurrentDebugFiberInDEV(fiber);
2383
+ try {
2384
+ commitPassiveMountOnFiber(root, fiber);
2385
+ } catch (error) {
2386
+ captureCommitPhaseError(fiber, fiber.return, error);
2387
}
2388
+ resetCurrentDebugFiberInDEV();
2389
}
2390
2391
if (fiber === subtreeRoot) {
@@ -2810,25 +2662,19 @@ function invokeLayoutEffectMountInDEV(fiber: Fiber): void {
2662
case FunctionComponent:
2663
case ForwardRef:
2664
case SimpleMemoComponent: {
2813
- invokeGuardedCallback(
2814
- null,
2815
- commitHookEffectListMount,
2816
- null,
2817
- HookLayout | HookHasEffect,
2818
- fiber,
2819
- );
2820
- if (hasCaughtError()) {
2821
- const mountError = clearCaughtError();
2822
- captureCommitPhaseError(fiber, fiber.return, mountError);
2665
+ try {
2666
+ commitHookEffectListMount(HookLayout | HookHasEffect, fiber);
2667
+ } catch (error) {
2668
+ captureCommitPhaseError(fiber, fiber.return, error);
2669
}
2670
break;
2671
}
2672
case ClassComponent: {
2673
const instance = fiber.stateNode;
2828
- invokeGuardedCallback(null, instance.componentDidMount, instance);
2829
- if (hasCaughtError()) {
2830
- const mountError = clearCaughtError();
2831
- captureCommitPhaseError(fiber, fiber.return, mountError);
2674
+ try {
2675
+ instance.componentDidMount();
2676
+ } catch (error) {
2677
+ captureCommitPhaseError(fiber, fiber.return, error);
2678
}
2679
break;
2680
}
@@ -2844,16 +2690,10 @@ function invokePassiveEffectMountInDEV(fiber: Fiber): void {
2690
case FunctionComponent:
2691
case ForwardRef:
2692
case SimpleMemoComponent: {
2847
- invokeGuardedCallback(
2848
- null,
2849
- commitHookEffectListMount,
2850
- null,
2851
- HookPassive | HookHasEffect,
2852
- fiber,
2853
- );
2854
- if (hasCaughtError()) {
2855
- const mountError = clearCaughtError();
2856
- captureCommitPhaseError(fiber, fiber.return, mountError);
2693
+ try {
2694
+ commitHookEffectListMount(HookPassive | HookHasEffect, fiber);
2695
+ } catch (error) {
2696
+ captureCommitPhaseError(fiber, fiber.return, error);
2697
}
2698
break;
2699
}
@@ -2869,35 +2709,21 @@ function invokeLayoutEffectUnmountInDEV(fiber: Fiber): void {
2709
case FunctionComponent:
2710
case ForwardRef:
2711
case SimpleMemoComponent: {
2872
- invokeGuardedCallback(
2873
- null,
2874
- commitHookEffectListUnmount,
2875
- null,
2876
- HookLayout | HookHasEffect,
2877
- fiber,
2878
- fiber.return,
2879
- );
2880
- if (hasCaughtError()) {
2881
- const unmountError = clearCaughtError();
2882
- captureCommitPhaseError(fiber, fiber.return, unmountError);
2712
+ try {
2713
+ commitHookEffectListUnmount(
2714
+ HookLayout | HookHasEffect,
2715
+ fiber,
2716
+ fiber.return,
2717
+ );
2718
+ } catch (error) {
2719
+ captureCommitPhaseError(fiber, fiber.return, error);
2720
}
2721
break;
2722
}
2723
case ClassComponent: {
2724
const instance = fiber.stateNode;
2725
if (typeof instance.componentWillUnmount === 'function') {
2889
- invokeGuardedCallback(
2890
- null,
2891
- safelyCallComponentWillUnmount,
2892
- null,
2893
- fiber,
2894
- fiber.return,
2895
- instance,
2896
- );
2897
- if (hasCaughtError()) {
2898
- const unmountError = clearCaughtError();
2899
- captureCommitPhaseError(fiber, fiber.return, unmountError);
2900
- }
2726
+ safelyCallComponentWillUnmount(fiber, fiber.return, instance);
2727
}
2728
break;
2729
}
@@ -2913,19 +2739,15 @@ function invokePassiveEffectUnmountInDEV(fiber: Fiber): void {
2739
case FunctionComponent:
2740
case ForwardRef:
2741
case SimpleMemoComponent: {
2916
- invokeGuardedCallback(
2917
- null,
2918
- commitHookEffectListUnmount,
2919
- null,
2920
- HookPassive | HookHasEffect,
2921
- fiber,
2922
- fiber.return,
2923
- );
2924
- if (hasCaughtError()) {
2925
- const unmountError = clearCaughtError();
2926
- captureCommitPhaseError(fiber, fiber.return, unmountError);
2742
+ try {
2743
+ commitHookEffectListUnmount(
2744
+ HookPassive | HookHasEffect,
2745
+ fiber,
2746
+ fiber.return,
2747
+ );
2748
+ } catch (error) {
2749
+ captureCommitPhaseError(fiber, fiber.return, error);
2750
}
2928
- break;
2751
}
2752
}
2753
}
packages/react-reconciler/src/__tests__/ReactSuspenseCallback-test.js
-65
@@ -244,69 +244,4 @@ describe('ReactSuspense', () => {
244
expect(ops1).toEqual([]);
245
expect(ops2).toEqual([]);
246
});
247
-
248
- if (__DEV__) {
249
- // @gate www
250
- it('regression test for #16215 that relies on implementation details', async () => {
251
- // Regression test for https://github.com/facebook/react/pull/16215.
252
- // The bug only happens if there's an error earlier in the commit phase.
253
- // The first error is the one that gets thrown, so to observe the later
254
- // error, I've mocked the ReactErrorUtils module.
255
- //
256
- // If this test starts failing because the implementation details change,
257
- // you can probably just delete it. It's not worth the hassle.
258
- jest.resetModules();
259
-
260
- const errors = [];
261
- let hasCaughtError = false;
262
- jest.mock('shared/ReactErrorUtils', () => ({
263
- invokeGuardedCallback(name, fn, context, ...args) {
264
- try {
265
- return fn.call(context, ...args);
266
- } catch (error) {
267
- hasCaughtError = true;
268
- errors.push(error);
269
- }
270
- },
271
- hasCaughtError() {
272
- return hasCaughtError;
273
- },
274
- clearCaughtError() {
275
- hasCaughtError = false;
276
- return errors[errors.length - 1];
277
- },
278
- }));
279
-
280
- React = require('react');
281
- ReactNoop = require('react-noop-renderer');
282
- Scheduler = require('scheduler');
283
-
284
- const {useEffect} = React;
285
- const {PromiseComp} = createThenable();
286
- function App() {
287
- useEffect(() => {
288
- Scheduler.unstable_yieldValue('Passive Effect');
289
- });
290
- return (
291
- <React.Suspense
292
- suspenseCallback={() => {
293
- throw Error('Oops!');
294
- }}
295
- fallback="Loading...">
296
- <PromiseComp />
297
- </React.Suspense>
298
- );
299
- }
300
- const root = ReactNoop.createRoot();
301
- await ReactNoop.act(async () => {
302
- root.render(<App />);
303
- expect(Scheduler).toFlushAndThrow('Oops!');
304
- });
305
-
306
- // Should have only received a single error. Before the bug fix, there was
307
- // also a second error related to the Suspense update queue.
308
- expect(errors.length).toBe(1);
309
- expect(errors[0].message).toEqual('Oops!');
310
- });
311
- }
247
});