33
var ErrorBoundary;
34
var ErrorMessage;
35
var NoopErrorBoundary;
36
+ var RethrowErrorBoundary;
37
var Normal;
38
39
beforeEach(() => {
395
log.push('NoopErrorBoundary componentWillUnmount');
396
}
397
unstable_handleError() {
397
- log.push('NoopErrorBoundary unstable_handleError');
398
+ if (ReactDOMFeatureFlags.useFiber) {
399
+ log.push('NoopErrorBoundary unstable_handleError');
400
+ } else {
401
+ // In Stack, not calling setState() is treated as a rethrow.
402
+ log.push('NoopErrorBoundary unstable_handleError [*]');
403
+ }
404
}
405
};
406
484
},
485
};
486
487
+ RethrowErrorBoundary = class extends React.Component {
488
+ constructor(props) {
489
+ super(props);
490
+ log.push('RethrowErrorBoundary constructor');
491
+ }
492
+ render() {
493
+ log.push('RethrowErrorBoundary render');
494
+ return <BrokenRender />;
495
+ }
496
+ componentWillMount() {
497
+ log.push('RethrowErrorBoundary componentWillMount');
498
+ }
499
+ componentDidMount() {
500
+ log.push('RethrowErrorBoundary componentDidMount');
501
+ }
502
+ componentWillUnmount() {
503
+ log.push('RethrowErrorBoundary componentWillUnmount');
504
+ }
505
+ unstable_handleError(error) {
506
+ if (!ReactDOMFeatureFlags.useFiber) {
507
+ log.push('RethrowErrorBoundary unstable_handleError [*]');
508
+ // In Stack, not calling setState() is treated as a rethrow.
509
+ return;
510
+ }
511
+ log.push('RethrowErrorBoundary unstable_handleError [!]');
512
+ throw error;
513
+ }
514
+ };
515
+
516
ErrorMessage = class extends React.Component {
517
constructor(props) {
518
super(props);
636
'BrokenRender constructor',
637
'BrokenRender componentWillMount',
638
'BrokenRender render [!]',
604
- // Catch and render an error message
605
- 'ErrorBoundary unstable_handleError',
639
...(ReactDOMFeatureFlags.useFiber ? [
607
- // The initial render was aborted, so
608
- // Fiber retries from the root.
609
- 'ErrorBoundary constructor',
610
- 'ErrorBoundary componentWillMount',
611
- ] : []),
612
- 'ErrorBoundary render error',
613
- 'ErrorBoundary componentDidMount',
640
+ // Fiber mounts with null children before capturing error
641
+ 'ErrorBoundary componentDidMount',
642
+ // Catch and render an error message
643
+ 'ErrorBoundary unstable_handleError',
644
+ 'ErrorBoundary componentWillUpdate',
645
+ 'ErrorBoundary render error',
646
+ 'ErrorBoundary componentDidUpdate',
647
+ ] : [
648
+ // Catch and render an error message
649
+ 'ErrorBoundary unstable_handleError',
650
+ 'ErrorBoundary render error',
651
+ 'ErrorBoundary componentDidMount',
652
+ ]),
653
]);
654
655
log.length = 0;
673
'ErrorBoundary componentWillMount',
674
'ErrorBoundary render success',
675
'BrokenConstructor constructor [!]',
637
- // Catch and render an error message
638
- 'ErrorBoundary unstable_handleError',
676
...(ReactDOMFeatureFlags.useFiber ? [
640
- // The initial render was aborted, so
641
- // Fiber retries from the root.
642
- 'ErrorBoundary constructor',
643
- 'ErrorBoundary componentWillMount',
644
- ] : []),
645
- 'ErrorBoundary render error',
646
- 'ErrorBoundary componentDidMount',
677
+ // Fiber mounts with null children before capturing error
678
+ 'ErrorBoundary componentDidMount',
679
+ // Catch and render an error message
680
+ 'ErrorBoundary unstable_handleError',
681
+ 'ErrorBoundary componentWillUpdate',
682
+ 'ErrorBoundary render error',
683
+ 'ErrorBoundary componentDidUpdate',
684
+ ] : [
685
+ // Catch and render an error message
686
+ 'ErrorBoundary unstable_handleError',
687
+ 'ErrorBoundary render error',
688
+ 'ErrorBoundary componentDidMount',
689
+ ]),
690
]);
691
692
log.length = 0;
711
'ErrorBoundary render success',
712
'BrokenComponentWillMount constructor',
713
'BrokenComponentWillMount componentWillMount [!]',
671
- // Catch and render an error message
672
- 'ErrorBoundary unstable_handleError',
714
...(ReactDOMFeatureFlags.useFiber ? [
674
- // The initial render was aborted, so
675
- // Fiber retries from the root.
676
- 'ErrorBoundary constructor',
677
- 'ErrorBoundary componentWillMount',
678
- ] : []),
679
- 'ErrorBoundary render error',
680
- 'ErrorBoundary componentDidMount',
715
+ 'ErrorBoundary componentDidMount',
716
+ 'ErrorBoundary unstable_handleError',
717
+ 'ErrorBoundary componentWillUpdate',
718
+ 'ErrorBoundary render error',
719
+ 'ErrorBoundary componentDidUpdate',
720
+ ] : [
721
+ // Catch and render an error message
722
+ 'ErrorBoundary unstable_handleError',
723
+ 'ErrorBoundary render error',
724
+ 'ErrorBoundary componentDidMount',
725
+ ]),
726
]);
727
728
log.length = 0;
753
'BrokenRender constructor',
754
'BrokenRender componentWillMount',
755
'BrokenRender render [!]',
711
- // Handle the error:
712
- 'ErrorBoundary unstable_handleError',
756
...(ReactDOMFeatureFlags.useFiber ? [
714
- // The initial render was aborted, so
715
- // Fiber retries from the root.
716
- 'ErrorBoundary constructor',
717
- 'ErrorBoundary componentWillMount',
718
- ] : []),
719
- 'ErrorBoundary render error',
720
- // Mount the error message:
721
- 'ErrorMessage constructor',
722
- 'ErrorMessage componentWillMount',
723
- 'ErrorMessage render',
724
- 'ErrorMessage componentDidMount',
725
- 'ErrorBoundary componentDidMount',
757
+ 'ErrorBoundary componentDidMount',
758
+ 'ErrorBoundary unstable_handleError',
759
+ 'ErrorBoundary componentWillUpdate',
760
+ 'ErrorBoundary render error',
761
+ 'ErrorMessage constructor',
762
+ 'ErrorMessage componentWillMount',
763
+ 'ErrorMessage render',
764
+ 'ErrorMessage componentDidMount',
765
+ 'ErrorBoundary componentDidUpdate',
766
+ ] : [
767
+ // Handle the error:
768
+ 'ErrorBoundary unstable_handleError',
769
+ 'ErrorBoundary render error',
770
+ // Mount the error message:
771
+ 'ErrorMessage constructor',
772
+ 'ErrorMessage componentWillMount',
773
+ 'ErrorMessage render',
774
+ 'ErrorMessage componentDidMount',
775
+ 'ErrorBoundary componentDidMount',
776
+ ]),
777
]);
778
779
log.length = 0;
788
var container = document.createElement('div');
789
ReactDOM.render(
790
<ErrorBoundary>
740
- <NoopErrorBoundary>
791
+ <RethrowErrorBoundary>
792
<BrokenRender />
742
- </NoopErrorBoundary>
793
+ </RethrowErrorBoundary>
794
</ErrorBoundary>,
795
container
796
);
799
'ErrorBoundary constructor',
800
'ErrorBoundary componentWillMount',
801
'ErrorBoundary render success',
751
- 'NoopErrorBoundary constructor',
752
- 'NoopErrorBoundary componentWillMount',
753
- 'NoopErrorBoundary render',
754
- 'BrokenRender constructor',
755
- 'BrokenRender componentWillMount',
756
- 'BrokenRender render [!]',
757
- // The first error boundary catches the error.
758
- // However, it doesn't adjust its state so next render will also fail.
759
- 'NoopErrorBoundary unstable_handleError',
760
- ...(ReactDOMFeatureFlags.useFiber ? [
761
- // The initial render was aborted, so
762
- // Fiber retries from the root.
763
- 'ErrorBoundary constructor',
764
- 'ErrorBoundary componentWillMount',
765
- 'ErrorBoundary render success',
766
- 'NoopErrorBoundary constructor',
767
- 'NoopErrorBoundary componentWillMount',
768
- ] : []),
769
- 'NoopErrorBoundary render',
802
+ 'RethrowErrorBoundary constructor',
803
+ 'RethrowErrorBoundary componentWillMount',
804
+ 'RethrowErrorBoundary render',
805
'BrokenRender constructor',
806
'BrokenRender componentWillMount',
807
'BrokenRender render [!]',
773
- // This time, the error propagates to the higher boundary
774
- 'ErrorBoundary unstable_handleError',
808
...(ReactDOMFeatureFlags.useFiber ? [
776
- // The initial render was aborted, so
777
- // Fiber retries from the root.
778
- 'ErrorBoundary constructor',
779
- 'ErrorBoundary componentWillMount',
780
- ] : []),
781
- // Render the error
782
- 'ErrorBoundary render error',
783
- 'ErrorBoundary componentDidMount',
809
+ // In Fiber, noop error boundaries render null
810
+ 'RethrowErrorBoundary componentDidMount',
811
+ 'ErrorBoundary componentDidMount',
812
+ 'RethrowErrorBoundary unstable_handleError [!]',
813
+ // The error got rethrown here.
814
+ // This time, the error propagates to the higher boundary
815
+ 'RethrowErrorBoundary componentWillUnmount',
816
+ 'ErrorBoundary unstable_handleError',
817
+ // Render the error
818
+ 'ErrorBoundary componentWillUpdate',
819
+ 'ErrorBoundary render error',
820
+ 'ErrorBoundary componentDidUpdate',
821
+ ] : [
822
+ // The first error boundary catches the error.
823
+ // However, it doesn't adjust its state so next render will also fail.
824
+ 'RethrowErrorBoundary unstable_handleError [*]',
825
+ 'RethrowErrorBoundary render',
826
+ 'BrokenRender constructor',
827
+ 'BrokenRender componentWillMount',
828
+ 'BrokenRender render [!]',
829
+ // This time, the error propagates to the higher boundary
830
+ 'ErrorBoundary unstable_handleError',
831
+ // Render the error
832
+ 'ErrorBoundary render error',
833
+ 'ErrorBoundary componentDidMount',
834
+ ]),
835
]);
836
837
log.length = 0;
857
'BrokenComponentWillMountErrorBoundary constructor',
858
'BrokenComponentWillMountErrorBoundary componentWillMount [!]',
859
// The error propagates to the higher boundary
809
- 'ErrorBoundary unstable_handleError',
860
...(ReactDOMFeatureFlags.useFiber ? [
811
- // The initial render was aborted, so
812
- // Fiber retries from the root.
813
- 'ErrorBoundary constructor',
814
- 'ErrorBoundary componentWillMount',
815
- ] : []),
816
- // Render the error
817
- 'ErrorBoundary render error',
818
- 'ErrorBoundary componentDidMount',
861
+ 'ErrorBoundary componentDidMount',
862
+ 'ErrorBoundary unstable_handleError',
863
+ 'ErrorBoundary componentWillUpdate',
864
+ 'ErrorBoundary render error',
865
+ 'ErrorBoundary componentDidUpdate',
866
+ ] : [
867
+ 'ErrorBoundary unstable_handleError',
868
+ // Render the error
869
+ 'ErrorBoundary render error',
870
+ 'ErrorBoundary componentDidMount',
871
+ ]),
872
]);
873
874
log.length = 0;
901
'BrokenRender render [!]',
902
// The first error boundary catches the error
903
// It adjusts state but throws displaying the message
851
- 'BrokenRenderErrorBoundary unstable_handleError',
904
...(ReactDOMFeatureFlags.useFiber ? [
853
- // The initial render was aborted, so
854
- // Fiber retries from the root.
855
- 'ErrorBoundary constructor',
856
- 'ErrorBoundary componentWillMount',
857
- 'ErrorBoundary render success',
858
- 'BrokenRenderErrorBoundary constructor',
859
- 'BrokenRenderErrorBoundary componentWillMount',
860
- ] : []),
861
- 'BrokenRenderErrorBoundary render error [!]',
862
- // The error propagates to the higher boundary
863
- 'ErrorBoundary unstable_handleError',
864
- ...(ReactDOMFeatureFlags.useFiber ? [
865
- // The initial render was aborted, so
866
- // Fiber retries from the root.
867
- 'ErrorBoundary constructor',
868
- 'ErrorBoundary componentWillMount',
869
- ] : []),
870
- // Render the error
871
- 'ErrorBoundary render error',
872
- 'ErrorBoundary componentDidMount',
905
+ // Finish mounting with null children
906
+ 'BrokenRenderErrorBoundary componentDidMount',
907
+ 'ErrorBoundary componentDidMount',
908
+ // Attempt to handle the error
909
+ 'BrokenRenderErrorBoundary unstable_handleError',
910
+ 'BrokenRenderErrorBoundary render error [!]',
911
+ // Boundary fails with new error, propagate to next boundary
912
+ 'BrokenRenderErrorBoundary componentWillUnmount',
913
+ // Attempt to handle the error again
914
+ 'ErrorBoundary unstable_handleError',
915
+ 'ErrorBoundary componentWillUpdate',
916
+ 'ErrorBoundary render error',
917
+ 'ErrorBoundary componentDidUpdate',
918
+ ] : [
919
+ 'BrokenRenderErrorBoundary unstable_handleError',
920
+ 'BrokenRenderErrorBoundary render error [!]',
921
+ // The error propagates to the higher boundary
922
+ 'ErrorBoundary unstable_handleError',
923
+ // Render the error
924
+ 'ErrorBoundary render error',
925
+ 'ErrorBoundary componentDidMount',
926
+ ]),
927
]);
928
929
log.length = 0;
956
'BrokenRender constructor',
957
'BrokenRender componentWillMount',
958
'BrokenRender render [!]',
905
- // Error boundary catches the error
906
- 'ErrorBoundary unstable_handleError',
959
...(ReactDOMFeatureFlags.useFiber ? [
908
- // The initial render was aborted, so
909
- // Fiber retries from the root.
910
- 'ErrorBoundary constructor',
911
- 'ErrorBoundary componentWillMount',
912
- ] : []),
913
- // Render the error message
914
- 'ErrorBoundary render error',
915
- 'ErrorBoundary componentDidMount',
960
+ // Finish mounting with null children
961
+ 'ErrorBoundary componentDidMount',
962
+ // Handle the error
963
+ 'ErrorBoundary unstable_handleError',
964
+ // Render the error message
965
+ 'ErrorBoundary componentWillUpdate',
966
+ 'ErrorBoundary render error',
967
+ 'ErrorBoundary componentDidUpdate',
968
+ ] : [
969
+ 'ErrorBoundary unstable_handleError',
970
+ // Render the error message
971
+ 'ErrorBoundary render error',
972
+ 'ErrorBoundary componentDidMount',
973
+ ]),
974
]);
975
976
log.length = 0;
1005
'BrokenRender componentWillMount',
1006
'BrokenRender render [!]',
1007
// Handle error:
950
- 'ErrorBoundary unstable_handleError',
1008
...(ReactDOMFeatureFlags.useFiber ? [
952
- // The initial render was aborted, so
953
- // Fiber retries from the root.
954
- 'ErrorBoundary constructor',
955
- 'ErrorBoundary componentWillMount',
1009
+ // Finish mounting with null children
1010
+ 'ErrorBoundary componentDidMount',
1011
+ // Handle the error
1012
+ 'ErrorBoundary unstable_handleError',
1013
+ // Render the error message
1014
+ 'ErrorBoundary componentWillUpdate',
1015
+ 'ErrorBoundary render error',
1016
+ 'Error message ref is set to [object HTMLDivElement]',
1017
+ 'ErrorBoundary componentDidUpdate',
1018
] : [
1019
+ 'ErrorBoundary unstable_handleError',
1020
// Stack reconciler resets ref on update, as it doesn't know ref was never set.
1021
// This is unnecessary, and Fiber doesn't do it:
1022
'Child ref is set to null',
1023
+ 'ErrorBoundary render error',
1024
+ // Ref to error message should get set:
1025
+ 'Error message ref is set to [object HTMLDivElement]',
1026
+ 'ErrorBoundary componentDidMount',
1027
]),
961
- 'ErrorBoundary render error',
962
- // Ref to error message should get set:
963
- 'Error message ref is set to [object HTMLDivElement]',
964
- 'ErrorBoundary componentDidMount',
1028
]);
1029
1030
log.length = 0;
1090
'Normal2 render',
1091
// BrokenConstructor will abort rendering:
1092
'BrokenConstructor constructor [!]',
1030
- 'ErrorBoundary unstable_handleError',
1093
...(ReactDOMFeatureFlags.useFiber ? [
1032
- // The initial render was aborted, so
1033
- // Fiber retries from the root.
1034
- 'ErrorBoundary componentWillReceiveProps',
1094
+ // Finish updating with null children
1095
+ 'Normal componentWillUnmount',
1096
+ 'ErrorBoundary componentDidUpdate',
1097
+ // Handle the error
1098
+ 'ErrorBoundary unstable_handleError',
1099
+ // Render the error message
1100
'ErrorBoundary componentWillUpdate',
1036
- // Fiber renders first, then unmounts in a batch:
1101
'ErrorBoundary render error',
1038
- 'Normal componentWillUnmount',
1102
+ 'ErrorBoundary componentDidUpdate',
1103
] : [
1104
+ 'ErrorBoundary unstable_handleError',
1105
// Stack unmounts first, then renders:
1106
'Normal componentWillUnmount',
1107
'ErrorBoundary render error',
1108
+ // Normal2 does not get lifefycle because it was never mounted
1109
+ 'ErrorBoundary componentDidUpdate',
1110
]),
1044
- // Normal2 does not get lifefycle because it was never mounted
1045
- 'ErrorBoundary componentDidUpdate',
1111
]);
1112
1113
log.length = 0;
1150
// BrokenComponentWillMount will abort rendering:
1151
'BrokenComponentWillMount constructor',
1152
'BrokenComponentWillMount componentWillMount [!]',
1088
- 'ErrorBoundary unstable_handleError',
1153
...(ReactDOMFeatureFlags.useFiber ? [
1090
- // The initial render was aborted, so
1091
- // Fiber retries from the root.
1092
- 'ErrorBoundary componentWillReceiveProps',
1154
+ // Finish updating with null children
1155
+ 'Normal componentWillUnmount',
1156
+ 'ErrorBoundary componentDidUpdate',
1157
+ // Handle the error
1158
+ 'ErrorBoundary unstable_handleError',
1159
+ // Render the error message
1160
'ErrorBoundary componentWillUpdate',
1094
- // Fiber renders first, then unmounts in a batch:
1161
'ErrorBoundary render error',
1096
- 'Normal componentWillUnmount',
1162
+ 'ErrorBoundary componentDidUpdate',
1163
] : [
1164
+ 'ErrorBoundary unstable_handleError',
1165
// Stack unmounts first, then renders:
1166
'Normal componentWillUnmount',
1167
'ErrorBoundary render error',
1168
+ // Normal2 does not get lifefycle because it was never mounted
1169
+ 'ErrorBoundary componentDidUpdate',
1170
]),
1102
- // Normal2 does not get lifefycle because it was never mounted
1103
- 'ErrorBoundary componentDidUpdate',
1171
]);
1172
1173
log.length = 0;
1205
'Normal render',
1206
// BrokenComponentWillReceiveProps will abort rendering:
1207
'BrokenComponentWillReceiveProps componentWillReceiveProps [!]',
1141
- 'ErrorBoundary unstable_handleError',
1208
...(ReactDOMFeatureFlags.useFiber ? [
1143
- // The initial render was aborted, so
1144
- // Fiber retries from the root.
1145
- 'ErrorBoundary componentWillReceiveProps',
1146
- 'ErrorBoundary componentWillUpdate',
1147
- // Fiber renders first, then unmounts in a batch:
1148
- 'ErrorBoundary render error',
1209
+ // Finish updating with null children
1210
'Normal componentWillUnmount',
1211
'BrokenComponentWillReceiveProps componentWillUnmount',
1212
+ 'ErrorBoundary componentDidUpdate',
1213
+ // Handle the error
1214
+ 'ErrorBoundary unstable_handleError',
1215
+ 'ErrorBoundary componentWillUpdate',
1216
+ 'ErrorBoundary render error',
1217
+ 'ErrorBoundary componentDidUpdate',
1218
] : [
1219
+ 'ErrorBoundary unstable_handleError',
1220
// Stack unmounts first, then renders:
1221
'Normal componentWillUnmount',
1222
'BrokenComponentWillReceiveProps componentWillUnmount',
1223
'ErrorBoundary render error',
1224
+ 'ErrorBoundary componentDidUpdate',
1225
]),
1157
- 'ErrorBoundary componentDidUpdate',
1226
]);
1227
1228
log.length = 0;
1261
// BrokenComponentWillUpdate will abort rendering:
1262
'BrokenComponentWillUpdate componentWillReceiveProps',
1263
'BrokenComponentWillUpdate componentWillUpdate [!]',
1196
- 'ErrorBoundary unstable_handleError',
1264
...(ReactDOMFeatureFlags.useFiber ? [
1198
- // The initial render was aborted, so
1199
- // Fiber retries from the root.
1200
- 'ErrorBoundary componentWillReceiveProps',
1201
- 'ErrorBoundary componentWillUpdate',
1202
- // Fiber renders first, then unmounts in a batch:
1203
- 'ErrorBoundary render error',
1265
+ // Finish updating with null children
1266
'Normal componentWillUnmount',
1267
'BrokenComponentWillUpdate componentWillUnmount',
1268
+ 'ErrorBoundary componentDidUpdate',
1269
+ // Handle the error
1270
+ 'ErrorBoundary unstable_handleError',
1271
+ 'ErrorBoundary componentWillUpdate',
1272
+ 'ErrorBoundary render error',
1273
+ 'ErrorBoundary componentDidUpdate',
1274
] : [
1275
+ 'ErrorBoundary unstable_handleError',
1276
// Stack unmounts first, then renders:
1277
'Normal componentWillUnmount',
1278
'BrokenComponentWillUpdate componentWillUnmount',
1279
'ErrorBoundary render error',
1280
+ 'ErrorBoundary componentDidUpdate',
1281
]),
1212
- 'ErrorBoundary componentDidUpdate',
1282
]);
1283
1284
log.length = 0;
1322
'BrokenRender constructor',
1323
'BrokenRender componentWillMount',
1324
'BrokenRender render [!]',
1256
- 'ErrorBoundary unstable_handleError',
1325
...(ReactDOMFeatureFlags.useFiber ? [
1258
- // The initial render was aborted, so
1259
- // Fiber retries from the root.
1260
- 'ErrorBoundary componentWillReceiveProps',
1326
+ // Finish updating with null children
1327
+ 'Normal componentWillUnmount',
1328
+ 'ErrorBoundary componentDidUpdate',
1329
+ // Handle the error
1330
+ 'ErrorBoundary unstable_handleError',
1331
'ErrorBoundary componentWillUpdate',
1262
- // Fiber renders first, then unmounts in a batch:
1332
'ErrorBoundary render error',
1264
- 'Normal componentWillUnmount',
1333
+ 'ErrorBoundary componentDidUpdate',
1334
] : [
1335
+ 'ErrorBoundary unstable_handleError',
1336
// Stack unmounts first, then renders:
1337
'Normal componentWillUnmount',
1338
'ErrorBoundary render error',
1339
+ // Normal2 does not get lifefycle because it was never mounted
1340
+ 'ErrorBoundary componentDidUpdate',
1341
]),
1270
- // Normal2 does not get lifefycle because it was never mounted
1271
- 'ErrorBoundary componentDidUpdate',
1342
]);
1343
1344
log.length = 0;
1392
'BrokenRender constructor',
1393
'BrokenRender componentWillMount',
1394
'BrokenRender render [!]',
1325
- 'ErrorBoundary unstable_handleError',
1395
...(ReactDOMFeatureFlags.useFiber ? [
1327
- // The initial render was aborted, so
1328
- // Fiber retries from the root.
1329
- 'ErrorBoundary componentWillReceiveProps',
1396
+ // Finish updating with null children
1397
+ 'Child1 ref is set to null',
1398
+ 'ErrorBoundary componentDidUpdate',
1399
+ // Handle the error
1400
+ 'ErrorBoundary unstable_handleError',
1401
'ErrorBoundary componentWillUpdate',
1331
- // Fiber renders first, resets refs later
1402
'ErrorBoundary render error',
1333
- 'Child1 ref is set to null',
1403
] : [
1404
+ 'ErrorBoundary unstable_handleError',
1405
// Stack resets ref first, renders later
1406
'Child1 ref is set to null',
1407
'ErrorBoundary render error',
1454
// The components have updated in this phase
1455
'BrokenComponentWillUnmount componentDidUpdate',
1456
'ErrorBoundary componentDidUpdate',
1387
- // Now that commit phase is done, Fiber handles errors
1457
+ // Now that commit phase is done, Fiber unmounts the boundary's children
1458
+ 'BrokenComponentWillUnmount componentWillUnmount [!]',
1459
'ErrorBoundary unstable_handleError',
1460
// The initial render was aborted, so
1461
// Fiber retries from the root.
1463
// Render an error now (stack will do it later)
1464
'ErrorBoundary render error',
1465
// Attempt to unmount previous child:
1395
- 'BrokenComponentWillUnmount componentWillUnmount [!]',
1466
// Done
1467
'ErrorBoundary componentDidUpdate',
1468
] : [
1524
'BrokenComponentWillUnmount componentDidUpdate',
1525
'Normal componentDidUpdate',
1526
'ErrorBoundary componentDidUpdate',
1527
+ 'Normal componentWillUnmount',
1528
+ 'BrokenComponentWillUnmount componentWillUnmount [!]',
1529
// Now that commit phase is done, Fiber handles errors
1530
'ErrorBoundary unstable_handleError',
1531
// The initial render was aborted, so
1533
'ErrorBoundary componentWillUpdate',
1534
// Render an error now (stack will do it later)
1535
'ErrorBoundary render error',
1464
- // Attempt to unmount previous child:
1465
- 'Normal componentWillUnmount',
1466
- 'BrokenComponentWillUnmount componentWillUnmount [!]',
1536
// Done
1537
'ErrorBoundary componentDidUpdate',
1538
] : [
1872
'LastChild componentDidMount',
1873
'ErrorBoundary componentDidMount',
1874
// Now we are ready to handle the error
1806
- 'ErrorBoundary unstable_handleError',
1807
- 'ErrorBoundary componentWillUpdate',
1808
- 'ErrorBoundary render error',
1875
// Safely unmount every child
1876
'BrokenComponentWillUnmount componentWillUnmount [!]',
1877
// Continue unmounting safely despite any errors
1878
'Normal componentWillUnmount',
1879
'BrokenComponentDidMount componentWillUnmount',
1880
'LastChild componentWillUnmount',
1881
+ // Handle the error
1882
+ 'ErrorBoundary unstable_handleError',
1883
+ 'ErrorBoundary componentWillUpdate',
1884
+ 'ErrorBoundary render error',
1885
// The update has finished
1886
'ErrorBoundary componentDidUpdate',
1887
]);
1919
// All lifecycles run
1920
'BrokenComponentDidUpdate componentDidUpdate [!]',
1921
'ErrorBoundary componentDidUpdate',
1922
+ 'BrokenComponentDidUpdate componentWillUnmount',
1923
// Then, error is handled
1924
'ErrorBoundary unstable_handleError',
1925
'ErrorBoundary componentWillUpdate',
1926
'ErrorBoundary render error',
1856
- 'BrokenComponentDidUpdate componentWillUnmount',
1927
'ErrorBoundary componentDidUpdate',
1928
]);
1929
1958
'BrokenComponentDidMountErrorBoundary componentDidMount [!]',
1959
// Fiber proceeds with the hooks
1960
'ErrorBoundary componentDidMount',
1961
+ 'BrokenComponentDidMountErrorBoundary componentWillUnmount',
1962
// The error propagates to the higher boundary
1963
'ErrorBoundary unstable_handleError',
1964
// Fiber retries from the root
1965
'ErrorBoundary componentWillUpdate',
1966
'ErrorBoundary render error',
1896
- 'BrokenComponentDidMountErrorBoundary componentWillUnmount',
1967
'ErrorBoundary componentDidUpdate',
1968
]);
1969
2042
'BrokenComponentDidUpdate componentDidUpdate [!]',
2043
'InnerUpdateBoundary componentDidUpdate',
2044
'OuterErrorBoundary componentDidUpdate',
1975
- // The interesting part starts now.
1976
- // Acknowledge errors independently but don't update yet:
2045
+ // After the commit phase, attempt to recover from any errors that
2046
+ // were captured
2047
'InnerUnmountBoundary unstable_handleError',
1978
- 'InnerUpdateBoundary unstable_handleError',
1979
- // Only two of four errors are acknowledged: one per boundary.
1980
- // The rest are likely cascading and we ignore them.
1981
- // Now update:
2048
'InnerUnmountBoundary componentWillUpdate',
2049
'InnerUnmountBoundary render error',
1984
- 'InnerUpdateBoundary componentWillUpdate',
1985
- 'InnerUpdateBoundary render error',
1986
- // Commit
2050
'BrokenComponentDidUpdate componentWillUnmount',
2051
'BrokenComponentDidUpdate componentWillUnmount',
2052
'InnerUnmountBoundary componentDidUpdate',
2053
+ 'InnerUpdateBoundary unstable_handleError',
2054
+ 'InnerUpdateBoundary componentWillUpdate',
2055
+ 'InnerUpdateBoundary render error',
2056
'InnerUpdateBoundary componentDidUpdate',
2057
]);
2058
2064
'InnerUpdateBoundary componentWillUnmount',
2065
]);
2066
});
2067
+
2068
+ it('discards a bad root if the root component fails', () => {
2069
+ spyOn(console, 'error');
2070
+
2071
+ const X = null;
2072
+ const Y = undefined;
2073
+ let err1;
2074
+ let err2;
2075
+
2076
+ try {
2077
+ let container = document.createElement('div');
2078
+ ReactDOM.render(<X />, container);
2079
+ } catch (err) {
2080
+ err1 = err;
2081
+ }
2082
+ try {
2083
+ let container = document.createElement('div');
2084
+ ReactDOM.render(<Y />, container);
2085
+ } catch (err) {
2086
+ err2 = err;
2087
+ }
2088
+
2089
+ expect(err1.message).toMatch(/got: null/);
2090
+ expect(err2.message).toMatch(/got: undefined/);
2091
+ });
2092
+
2093
+ it('renders empty output if error boundary does not handle the error', () => {
2094
+ var container = document.createElement('div');
2095
+ ReactDOM.render(
2096
+ <div>
2097
+ Sibling
2098
+ <NoopErrorBoundary>
2099
+ <BrokenRender />
2100
+ </NoopErrorBoundary>
2101
+ </div>,
2102
+ container
2103
+ );
2104
+ expect(container.firstChild.textContent).toBe('Sibling');
2105
+ expect(log).toEqual([
2106
+ 'NoopErrorBoundary constructor',
2107
+ 'NoopErrorBoundary componentWillMount',
2108
+ 'NoopErrorBoundary render',
2109
+ 'BrokenRender constructor',
2110
+ 'BrokenRender componentWillMount',
2111
+ 'BrokenRender render [!]',
2112
+ // In Fiber, noop error boundaries render null
2113
+ 'NoopErrorBoundary componentDidMount',
2114
+ 'NoopErrorBoundary unstable_handleError',
2115
+ // Nothing happens.
2116
+ ]);
2117
+
2118
+ log.length = 0;
2119
+ ReactDOM.unmountComponentAtNode(container);
2120
+ expect(log).toEqual([
2121
+ 'NoopErrorBoundary componentWillUnmount',
2122
+ ]);
2123
+ });
2124
}
2125
2126
});