[Fizz] Don't add aborted segments to the completedSegments list (#21976)
* Don't add aborted segments to the completedSegments list * Update error message to include aborted status
Sebastian Markbåge committed
Jul 27, 2021 at 21:53 UTC
321087d1343638e2d45e53971a7d8c384549940b
3 files changed
+50
-11
packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js
+31
@@ -1447,4 +1447,35 @@ describe('ReactDOMFizzServer', () => {
1447
1448
expect(loggedErrors).toEqual([theError]);
1449
});
1450
+
1451
+ // @gate experimental
1452
+ it('should be able to abort the fallback if the main content finishes first', async () => {
1453
+ await act(async () => {
1454
+ const {startWriting} = ReactDOMFizzServer.pipeToNodeWritable(
1455
+ <Suspense fallback={<Text text="Loading Outer" />}>
1456
+ <div>
1457
+ <Suspense
1458
+ fallback={
1459
+ <div>
1460
+ <AsyncText text="Loading" />
1461
+ Inner
1462
+ </div>
1463
+ }>
1464
+ <AsyncText text="Hello" />
1465
+ </Suspense>
1466
+ </div>
1467
+ </Suspense>,
1468
+ writable,
1469
+ );
1470
+ startWriting();
1471
+ });
1472
+ expect(getVisibleChildren(container)).toEqual('Loading Outer');
1473
+ // We should have received a partial segment containing the a partial of the fallback.
1474
+ expect(container.innerHTML).toContain('Inner');
1475
+ await act(async () => {
1476
+ resolveText('Hello');
1477
+ });
1478
+ // We should've been able to display the content without waiting for the rest of the fallback.
1479
+ expect(getVisibleChildren(container)).toEqual(<div>Hello</div>);
1480
+ });
1481
});
packages/react-server/src/ReactFizzServer.js
+18
-10
@@ -1408,7 +1408,11 @@ function finishedTask(
1408
// This must have been the last segment we were waiting on. This boundary is now complete.
1409
if (segment.parentFlushed) {
1410
// Our parent segment already flushed, so we need to schedule this segment to be emitted.
1411
- boundary.completedSegments.push(segment);
1411
+ // If it is a segment that was aborted, we'll write other content instead so we don't need
1412
+ // to emit it.
1413
+ if (segment.status === COMPLETED) {
1414
+ boundary.completedSegments.push(segment);
1415
+ }
1416
}
1417
if (boundary.parentFlushed) {
1418
// The segment might be part of a segment that didn't flush yet, but if the boundary's
@@ -1423,14 +1427,18 @@ function finishedTask(
1427
} else {
1428
if (segment.parentFlushed) {
1429
// Our parent already flushed, so we need to schedule this segment to be emitted.
1426
- const completedSegments = boundary.completedSegments;
1427
- completedSegments.push(segment);
1428
- if (completedSegments.length === 1) {
1429
- // This is the first time since we last flushed that we completed anything.
1430
- // We can schedule this boundary to emit its partially completed segments early
1431
- // in case the parent has already been flushed.
1432
- if (boundary.parentFlushed) {
1433
- request.partialBoundaries.push(boundary);
1430
+ // If it is a segment that was aborted, we'll write other content instead so we don't need
1431
+ // to emit it.
1432
+ if (segment.status === COMPLETED) {
1433
+ const completedSegments = boundary.completedSegments;
1434
+ completedSegments.push(segment);
1435
+ if (completedSegments.length === 1) {
1436
+ // This is the first time since we last flushed that we completed anything.
1437
+ // We can schedule this boundary to emit its partially completed segments early
1438
+ // in case the parent has already been flushed.
1439
+ if (boundary.parentFlushed) {
1440
+ request.partialBoundaries.push(boundary);
1441
+ }
1442
}
1443
}
1444
}
@@ -1570,7 +1578,7 @@ function flushSubtree(
1578
default: {
1579
invariant(
1580
false,
1573
- 'Errored or already flushed boundaries should not be flushed again. This is a bug in React.',
1581
+ 'Aborted, errored or already flushed boundaries should not be flushed again. This is a bug in React.',
1582
);
1583
}
1584
}
scripts/error-codes/codes.json
+1
-1
@@ -378,7 +378,7 @@
378
"387": "Should have a current fiber. This is a bug in React.",
379
"388": "Expected to find a bailed out fiber. This is a bug in React.",
380
"389": "There can only be one root segment. This is a bug in React.",
381
- "390": "Errored or already flushed boundaries should not be flushed again. This is a bug in React.",
381
+ "390": "Aborted, errored or already flushed boundaries should not be flushed again. This is a bug in React.",
382
"391": "A previously unvisited boundary must have exactly one root segment. This is a bug in React.",
383
"392": "A root segment ID must have been assigned by now. This is a bug in React.",
384
"393": "Cache cannot be refreshed during server rendering.",