@@ -1085,87 +1085,108 @@ function finishConcurrentRender(
1085
1085
finishedWork : Fiber ,
1086
1086
lanes : Lanes ,
1087
1087
) {
1088
- // TODO: The fact that most of these branches are identical suggests that some
1089
- // of the exit statuses are not best modeled as exit statuses and should be
1090
- // tracked orthogonally.
1091
1088
switch ( exitStatus ) {
1092
1089
case RootInProgress :
1093
1090
case RootFatalErrored : {
1094
1091
throw new Error ( 'Root did not complete. This is a bug in React.' ) ;
1095
1092
}
1093
+ case RootErrored : {
1094
+ // We should have already attempted to retry this tree. If we reached
1095
+ // this point, it errored again. Commit it.
1096
+ commitRootWhenReady (
1097
+ root ,
1098
+ finishedWork ,
1099
+ workInProgressRootRecoverableErrors ,
1100
+ workInProgressTransitions ,
1101
+ lanes ,
1102
+ ) ;
1103
+ break ;
1104
+ }
1105
+ case RootSuspended : {
1106
+ markRootSuspended ( root , lanes ) ;
1107
+
1108
+ // We have an acceptable loading state. We need to figure out if we
1109
+ // should immediately commit it or wait a bit.
1110
+
1111
+ if (
1112
+ includesOnlyRetries ( lanes ) &&
1113
+ // do not delay if we're inside an act() scope
1114
+ ! shouldForceFlushFallbacksInDEV ( )
1115
+ ) {
1116
+ // This render only included retries, no updates. Throttle committing
1117
+ // retries so that we don't show too many loading states too quickly.
1118
+ const msUntilTimeout =
1119
+ globalMostRecentFallbackTime + FALLBACK_THROTTLE_MS - now ( ) ;
1120
+ // Don't bother with a very short suspense time.
1121
+ if ( msUntilTimeout > 10 ) {
1122
+ const nextLanes = getNextLanes ( root , NoLanes ) ;
1123
+ if ( nextLanes !== NoLanes ) {
1124
+ // There's additional work on this root.
1125
+ break ;
1126
+ }
1127
+
1128
+ // The render is suspended, it hasn't timed out, and there's no
1129
+ // lower priority work to do. Instead of committing the fallback
1130
+ // immediately, wait for more data to arrive.
1131
+ root . timeoutHandle = scheduleTimeout (
1132
+ commitRootWhenReady . bind (
1133
+ null ,
1134
+ root ,
1135
+ finishedWork ,
1136
+ workInProgressRootRecoverableErrors ,
1137
+ workInProgressTransitions ,
1138
+ lanes ,
1139
+ ) ,
1140
+ msUntilTimeout ,
1141
+ ) ;
1142
+ break ;
1143
+ }
1144
+ }
1145
+ // The work expired. Commit immediately.
1146
+ commitRootWhenReady (
1147
+ root ,
1148
+ finishedWork ,
1149
+ workInProgressRootRecoverableErrors ,
1150
+ workInProgressTransitions ,
1151
+ lanes ,
1152
+ ) ;
1153
+ break ;
1154
+ }
1096
1155
case RootSuspendedWithDelay : {
1156
+ markRootSuspended ( root , lanes ) ;
1157
+
1097
1158
if ( includesOnlyTransitions ( lanes ) ) {
1098
1159
// This is a transition, so we should exit without committing a
1099
1160
// placeholder and without scheduling a timeout. Delay indefinitely
1100
1161
// until we receive more data.
1101
- markRootSuspended ( root , lanes ) ;
1102
- return ;
1162
+ break ;
1103
1163
}
1164
+
1104
1165
// Commit the placeholder.
1166
+ commitRootWhenReady (
1167
+ root ,
1168
+ finishedWork ,
1169
+ workInProgressRootRecoverableErrors ,
1170
+ workInProgressTransitions ,
1171
+ lanes ,
1172
+ ) ;
1105
1173
break ;
1106
1174
}
1107
- case RootErrored :
1108
- case RootSuspended :
1109
1175
case RootCompleted : {
1176
+ // The work completed.
1177
+ commitRootWhenReady (
1178
+ root ,
1179
+ finishedWork ,
1180
+ workInProgressRootRecoverableErrors ,
1181
+ workInProgressTransitions ,
1182
+ lanes ,
1183
+ ) ;
1110
1184
break ;
1111
1185
}
1112
1186
default : {
1113
1187
throw new Error ( 'Unknown root exit status.' ) ;
1114
1188
}
1115
1189
}
1116
-
1117
- if ( shouldForceFlushFallbacksInDEV ( ) ) {
1118
- // We're inside an `act` scope. Commit immediately.
1119
- commitRoot (
1120
- root ,
1121
- workInProgressRootRecoverableErrors ,
1122
- workInProgressTransitions ,
1123
- ) ;
1124
- } else {
1125
- if ( includesOnlyRetries ( lanes ) ) {
1126
- // This render only included retries, no updates. Throttle committing
1127
- // retries so that we don't show too many loading states too quickly.
1128
- const msUntilTimeout =
1129
- globalMostRecentFallbackTime + FALLBACK_THROTTLE_MS - now ( ) ;
1130
-
1131
- // Don't bother with a very short suspense time.
1132
- if ( msUntilTimeout > 10 ) {
1133
- markRootSuspended ( root , lanes ) ;
1134
-
1135
- const nextLanes = getNextLanes ( root , NoLanes ) ;
1136
- if ( nextLanes !== NoLanes ) {
1137
- // There's additional work we can do on this root. We might as well
1138
- // attempt to work on that while we're suspended.
1139
- return ;
1140
- }
1141
-
1142
- // The render is suspended, it hasn't timed out, and there's no
1143
- // lower priority work to do. Instead of committing the fallback
1144
- // immediately, wait for more data to arrive.
1145
- // TODO: Combine retry throttling with Suspensey commits. Right now they
1146
- // run one after the other.
1147
- root . timeoutHandle = scheduleTimeout (
1148
- commitRootWhenReady . bind (
1149
- null ,
1150
- root ,
1151
- finishedWork ,
1152
- workInProgressRootRecoverableErrors ,
1153
- workInProgressTransitions ,
1154
- lanes ,
1155
- ) ,
1156
- msUntilTimeout ,
1157
- ) ;
1158
- return ;
1159
- }
1160
- }
1161
- commitRootWhenReady (
1162
- root ,
1163
- finishedWork ,
1164
- workInProgressRootRecoverableErrors ,
1165
- workInProgressTransitions ,
1166
- lanes ,
1167
- ) ;
1168
- }
1169
1190
}
1170
1191
1171
1192
function commitRootWhenReady (
@@ -1175,8 +1196,6 @@ function commitRootWhenReady(
1175
1196
transitions : Array < Transition > | null ,
1176
1197
lanes : Lanes ,
1177
1198
) {
1178
- // TODO: Combine retry throttling with Suspensey commits. Right now they run
1179
- // one after the other.
1180
1199
if ( includesOnlyNonUrgentLanes ( lanes ) ) {
1181
1200
// Before committing, ask the renderer whether the host tree is ready.
1182
1201
// If it's not, we'll wait until it notifies us.
@@ -1199,15 +1218,22 @@ function commitRootWhenReady(
1199
1218
// us that it's ready. This will be canceled if we start work on the
1200
1219
// root again.
1201
1220
root . cancelPendingCommit = schedulePendingCommit (
1202
- commitRoot . bind ( null , root , recoverableErrors , transitions ) ,
1221
+ commitRoot . bind (
1222
+ null ,
1223
+ root ,
1224
+ workInProgressRootRecoverableErrors ,
1225
+ workInProgressTransitions ,
1226
+ ) ,
1203
1227
) ;
1204
- markRootSuspended ( root , lanes ) ;
1205
1228
return ;
1206
1229
}
1207
1230
}
1208
-
1209
1231
// Otherwise, commit immediately.
1210
- commitRoot ( root , recoverableErrors , transitions ) ;
1232
+ commitRoot (
1233
+ root ,
1234
+ workInProgressRootRecoverableErrors ,
1235
+ workInProgressTransitions ,
1236
+ ) ;
1211
1237
}
1212
1238
1213
1239
function isRenderConsistentWithExternalStores ( finishedWork : Fiber ) : boolean {
0 commit comments