@@ -1029,25 +1029,66 @@ function pushHaltedAwaitOnComponentStack(
10291029 }
10301030}
10311031
1032+ // performWork + retryTask without mutation
1033+ function rerenderHaltedTask ( request : Request , task : Task ) : void {
1034+ const prevContext = getActiveContext ( ) ;
1035+ const prevDispatcher = ReactSharedInternals . H ;
1036+ ReactSharedInternals . H = HooksDispatcher ;
1037+ const prevAsyncDispatcher = ReactSharedInternals . A ;
1038+ ReactSharedInternals . A = DefaultAsyncDispatcher ;
1039+
1040+ const prevRequest = currentRequest ;
1041+ currentRequest = request ;
1042+
1043+ const prevGetCurrentStackImpl = ReactSharedInternals . getCurrentStack ;
1044+ ReactSharedInternals . getCurrentStack = getCurrentStackInDEV ;
1045+
1046+ const prevResumableState = currentResumableState ;
1047+ setCurrentResumableState ( request . resumableState ) ;
1048+ switchContext ( task . context ) ;
1049+ const prevTaskInDEV = currentTaskInDEV ;
1050+ setCurrentTaskInDEV ( task ) ;
1051+ try {
1052+ retryNode ( request , task ) ;
1053+ } catch ( x ) {
1054+ // Suspended again.
1055+ resetHooksState ( ) ;
1056+ } finally {
1057+ setCurrentTaskInDEV ( prevTaskInDEV ) ;
1058+ setCurrentResumableState ( prevResumableState ) ;
1059+
1060+ ReactSharedInternals . H = prevDispatcher ;
1061+ ReactSharedInternals . A = prevAsyncDispatcher ;
1062+
1063+ ReactSharedInternals . getCurrentStack = prevGetCurrentStackImpl ;
1064+ if ( prevDispatcher === HooksDispatcher ) {
1065+ // This means that we were in a reentrant work loop. This could happen
1066+ // in a renderer that supports synchronous work like renderToString,
1067+ // when it's called from within another renderer.
1068+ // Normally we don't bother switching the contexts to their root/default
1069+ // values when leaving because we'll likely need the same or similar
1070+ // context again. However, when we're inside a synchronous loop like this
1071+ // we'll to restore the context to what it was before returning.
1072+ switchContext ( prevContext ) ;
1073+ }
1074+ currentRequest = prevRequest ;
1075+ }
1076+ }
1077+
10321078function pushSuspendedCallSiteOnComponentStack (
10331079 request : Request ,
10341080 task : Task ,
10351081) : void {
10361082 setCaptureSuspendedCallSiteDEV ( true ) ;
1037- let suspendCallSiteStack : ComponentStackNode | null = null ;
1038- let suspendCallSiteDebugTask : ConsoleTask | null = null ;
1039- const previousPingedTasks = request . pingedTasks ;
10401083 try {
1041- // TODO: Use a dedicated method to re-render instead of abusing ping.
1042- request . pingedTasks = [ task ] ;
1043- performWork ( request ) ;
1044- suspendCallSiteStack = getSuspendedCallSiteStackDEV ( ) ;
1045- suspendCallSiteDebugTask = getSuspendedCallSiteDebugTaskDEV ( ) ;
1084+ rerenderHaltedTask( request , task) ;
10461085 } finally {
1047- request . pingedTasks = previousPingedTasks ;
10481086 setCaptureSuspendedCallSiteDEV( false ) ;
10491087 }
10501088
1089+ const suspendCallSiteStack = getSuspendedCallSiteStackDEV ( ) ;
1090+ const suspendCallSiteDebugTask = getSuspendedCallSiteDebugTaskDEV ( ) ;
1091+
10511092 if ( suspendCallSiteStack !== null ) {
10521093 const ownerStack = task . componentStack ;
10531094 task . componentStack = {
@@ -4996,9 +5037,7 @@ function retryRenderTask(
49965037 task : RenderTask ,
49975038 segment : Segment ,
49985039) : void {
4999- // TODO: We only retry when aborted to get the suspended callsite.
5000- // Use a dedicated mechanism to re-render.
5001- if ( segment . status !== PENDING && segment . status !== ABORTED ) {
5040+ if ( segment . status !== PENDING ) {
50025041 // We completed this by other means before we had a chance to retry it.
50035042 return ;
50045043 }
0 commit comments