[Fizz] track postpones when aborting boundaries with a postpone (#30751)
When aborting with a postpone value boundaries are put into client rendered mode even during prerenders. This doesn't follow the postpoen semantics of the rest of fizz where during a prerender a postpone is tracked and it will leave holes in tracked postpone state that can be resumed. This change updates this behavior to match the postpones semantics between aborts and imperative postpones.
Josh Story committed
Aug 20, 2024 at 09:49 UTC
2505bf9b3400c6a00381e86d30b495935f5339df
2 files changed
+13
-2
packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js
-1
@@ -7727,7 +7727,6 @@ describe('ReactDOMFizzServer', () => {
7727
7728
const prerendered = await pendingPrerender;
7729
7730
- expect(prerendered.postponed).toBe(null);
7730
expect(errors).toEqual([]);
7731
expect(postpones).toEqual(['manufactured', 'manufactured']);
7732
packages/react-server/src/ReactFizzServer.js
+13
-1
@@ -3857,7 +3857,6 @@ function abortTask(task: Task, request: Request, error: mixed): void {
3857
} else {
3858
boundary.pendingTasks--;
3859
if (boundary.status !== CLIENT_RENDERED) {
3860
- boundary.status = CLIENT_RENDERED;
3860
// We construct an errorInfo from the boundary's componentStack so the error in dev will indicate which
3861
// boundary the message is referring to
3862
const errorInfo = getThrownInfo(task.componentStack);
@@ -3870,11 +3869,24 @@ function abortTask(task: Task, request: Request, error: mixed): void {
3869
) {
3870
const postponeInstance: Postpone = (error: any);
3871
logPostpone(request, postponeInstance.message, errorInfo, null);
3872
+ if (request.trackedPostpones !== null && segment !== null) {
3873
+ trackPostpone(request, request.trackedPostpones, task, segment);
3874
+ finishedTask(request, task.blockedBoundary, segment);
3875
+
3876
+ // If this boundary was still pending then we haven't already cancelled its fallbacks.
3877
+ // We'll need to abort the fallbacks, which will also error that parent boundary.
3878
+ boundary.fallbackAbortableTasks.forEach(fallbackTask =>
3879
+ abortTask(fallbackTask, request, error),
3880
+ );
3881
+ boundary.fallbackAbortableTasks.clear();
3882
+ return;
3883
+ }
3884
// TODO: Figure out a better signal than a magic digest value.
3885
errorDigest = 'POSTPONE';
3886
} else {
3887
errorDigest = logRecoverableError(request, error, errorInfo, null);
3888
}
3889
+ boundary.status = CLIENT_RENDERED;
3890
encodeErrorForBoundary(boundary, errorDigest, error, errorInfo, true);
3891
3892
untrackBoundary(request, boundary);