[Fizz] Reset the segent id assignment when postponing the root (#33755)

When postponing the root we encode the segment Id into the postponed
state but we should really be reseting it to zero so we can restart the
counter from the beginning when the resume is actually just a re-render.

This also no longer assigns the root segment id based on the postponed
state when resuming the root for the same reason. In the future we may
use the embedded replay segment id if we implement resuming the root
without re-rendering everything but that is not yet implemented or
planned.
This commit is contained in:
Josh Story 2025-07-10 12:12:09 -07:00 committed by GitHub
parent 96c61b7f1f
commit 463b808176
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 12 additions and 9 deletions

View File

@ -1623,7 +1623,7 @@ describe('ReactDOMFizzStaticBrowser', () => {
expect(result).toBe( expect(result).toBe(
'<!DOCTYPE html><html><head><link rel="expect" href="#_R_" blocking="render"/></head>' + '<!DOCTYPE html><html><head><link rel="expect" href="#_R_" blocking="render"/></head>' +
'<body>hello<!--$?--><template id="B:1"></template><!--/$--><script id="_R_">requestAnimationFrame(function(){$RT=performance.now()});</script>', '<body>hello<!--$?--><template id="B:0"></template><!--/$--><script id="_R_">requestAnimationFrame(function(){$RT=performance.now()});</script>',
); );
await 1; await 1;
@ -1648,8 +1648,8 @@ describe('ReactDOMFizzStaticBrowser', () => {
expect(slice).toBe( expect(slice).toBe(
'<!DOCTYPE html><html><head><link rel="expect" href="#_R_" blocking="render"/></head>' + '<!DOCTYPE html><html><head><link rel="expect" href="#_R_" blocking="render"/></head>' +
'<body>hello<!--$?--><template id="B:1"></template><!--/$--><script id="_R_">requestAnimationFrame(function(){$RT=performance.now()});</script>' + '<body>hello<!--$?--><template id="B:0"></template><!--/$--><script id="_R_">requestAnimationFrame(function(){$RT=performance.now()});</script>' +
'<div hidden id="S:1">world<!-- --></div><script>$RX', '<div hidden id="S:0">world<!-- --></div><script>$RX',
); );
}); });

View File

@ -666,7 +666,6 @@ export function resumeRequest(
request.nextSegmentId = postponedState.nextSegmentId; request.nextSegmentId = postponedState.nextSegmentId;
if (typeof postponedState.replaySlots === 'number') { if (typeof postponedState.replaySlots === 'number') {
const resumedId = postponedState.replaySlots;
// We have a resume slot at the very root. This is effectively just a full rerender. // We have a resume slot at the very root. This is effectively just a full rerender.
const rootSegment = createPendingSegment( const rootSegment = createPendingSegment(
request, request,
@ -677,7 +676,6 @@ export function resumeRequest(
false, false,
false, false,
); );
rootSegment.id = resumedId;
// There is no parent so conceptually, we're unblocked to flush this segment. // There is no parent so conceptually, we're unblocked to flush this segment.
rootSegment.parentFlushed = true; rootSegment.parentFlushed = true;
const rootTask = createRenderTask( const rootTask = createRenderTask(
@ -6326,6 +6324,7 @@ export function getPostponedState(request: Request): null | PostponedState {
return null; return null;
} }
let replaySlots: ResumeSlots; let replaySlots: ResumeSlots;
let nextSegmentId: number;
if ( if (
request.completedRootSegment !== null && request.completedRootSegment !== null &&
// The Root postponed // The Root postponed
@ -6333,17 +6332,21 @@ export function getPostponedState(request: Request): null | PostponedState {
// Or the Preamble was not available // Or the Preamble was not available
request.completedPreambleSegments === null) request.completedPreambleSegments === null)
) { ) {
// This is necessary for the pending preamble case and is idempotent for the nextSegmentId = 0;
// postponed root case // We need to ensure that on resume we retry the root. We use a number
replaySlots = request.completedRootSegment.id; // type for the replaySlots to signify this (see resumeRequest).
// The value -1 represents an unassigned ID but is not functionally meaningful
// for resuming at the root.
replaySlots = -1;
// We either postponed the root or we did not have a preamble to flush // We either postponed the root or we did not have a preamble to flush
resetResumableState(request.resumableState, request.renderState); resetResumableState(request.resumableState, request.renderState);
} else { } else {
nextSegmentId = request.nextSegmentId;
replaySlots = trackedPostpones.rootSlots; replaySlots = trackedPostpones.rootSlots;
completeResumableState(request.resumableState); completeResumableState(request.resumableState);
} }
return { return {
nextSegmentId: request.nextSegmentId, nextSegmentId,
rootFormatContext: request.rootFormatContext, rootFormatContext: request.rootFormatContext,
progressiveChunkSize: request.progressiveChunkSize, progressiveChunkSize: request.progressiveChunkSize,
resumableState: request.resumableState, resumableState: request.resumableState,