Skip to content

Commit

Permalink
onReadyToStream callback
Browse files Browse the repository at this point in the history
This is typically not needed because if you want to stream when the
root is ready you can just start writing immediately.
  • Loading branch information
sebmarkbage committed Mar 23, 2021
1 parent 4d22b70 commit 0509b57
Show file tree
Hide file tree
Showing 5 changed files with 32 additions and 9 deletions.
24 changes: 16 additions & 8 deletions packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,6 @@ describe('ReactDOMFizzServer', () => {
writable.write(chunk, encoding, next);
};

writable.write('<div id="container-A">');
await act(async () => {
const {startWriting} = ReactDOMFizzServer.pipeToNodeWritable(
<Suspense fallback={<Text text="Loading A..." />}>
Expand All @@ -346,13 +345,17 @@ describe('ReactDOMFizzServer', () => {
</div>
</Suspense>,
writableA,
{identifierPrefix: 'A_'},
{
identifierPrefix: 'A_',
onReadyToStream() {
writableA.write('<div id="container-A">');
startWriting();
writableA.write('</div>');
},
},
);
startWriting();
});
writable.write('</div>');

writable.write('<div id="container-B">');
await act(async () => {
const {startWriting} = ReactDOMFizzServer.pipeToNodeWritable(
<Suspense fallback={<Text text="Loading B..." />}>
Expand All @@ -362,11 +365,16 @@ describe('ReactDOMFizzServer', () => {
</div>
</Suspense>,
writableB,
{identifierPrefix: 'B_'},
{
identifierPrefix: 'B_',
onReadyToStream() {
writableB.write('<div id="container-B">');
startWriting();
writableB.write('</div>');
},
},
);
startWriting();
});
writable.write('</div>');

expect(getVisibleChildren(container)).toEqual([
<div id="container-A">Loading A...</div>,
Expand Down
2 changes: 2 additions & 0 deletions packages/react-dom/src/server/ReactDOMFizzServerBrowser.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ type Options = {
identifierPrefix?: string,
progressiveChunkSize?: number,
signal?: AbortSignal,
onReadyToStream?: () => void,
onComplete?: () => void,
onError?: (error: mixed) => void,
};
Expand All @@ -48,6 +49,7 @@ function renderToReadableStream(
options ? options.progressiveChunkSize : undefined,
options ? options.onError : undefined,
options ? options.onComplete : undefined,
options ? options.onReadyToStream : undefined,
);
startWork(request);
},
Expand Down
2 changes: 2 additions & 0 deletions packages/react-dom/src/server/ReactDOMFizzServerNode.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ function createDrainHandler(destination, request) {
type Options = {
identifierPrefix?: string,
progressiveChunkSize?: number,
onReadyToStream?: () => void,
onComplete?: () => void,
onError?: (error: mixed) => void,
};
Expand All @@ -48,6 +49,7 @@ function pipeToNodeWritable(
options ? options.progressiveChunkSize : undefined,
options ? options.onError : undefined,
options ? options.onComplete : undefined,
options ? options.onReadyToStream : undefined,
);
let hasStartedFlowing = false;
startWork(request);
Expand Down
2 changes: 2 additions & 0 deletions packages/react-noop-renderer/src/ReactNoopServer.js
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@ const ReactNoopServer = ReactFizzServer({

type Options = {
progressiveChunkSize?: number,
onReadyToStream?: () => void,
onComplete?: () => void,
onError?: (error: mixed) => void,
};
Expand All @@ -238,6 +239,7 @@ function render(children: React$Element<any>, options?: Options): Destination {
options ? options.progressiveChunkSize : undefined,
options ? options.onError : undefined,
options ? options.onComplete : undefined,
options ? options.onReadyToStream : undefined,
);
ReactNoopServer.startWork(request);
ReactNoopServer.startFlowing(request);
Expand Down
11 changes: 10 additions & 1 deletion packages/react-server/src/ReactFizzServer.js
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,10 @@ type Request = {
// onComplete is called when all pending work is done but it may not have flushed yet.
// This is a good time to start writing if you want only HTML and no intermediate steps.
onComplete: () => void,
// onReadyToStream is called when there is at least a root fallback ready to show.
// Typically you don't need this callback because it's best practice to always have a
// root fallback ready so there's no need to wait.
onReadyToStream: () => void,
};

// This is a default heuristic for how to split up the HTML content into progressive
Expand All @@ -141,6 +145,7 @@ export function createRequest(
progressiveChunkSize: number = DEFAULT_PROGRESSIVE_CHUNK_SIZE,
onError: (error: mixed) => void = noop,
onComplete: () => void = noop,
onReadyToStream: () => void = noop,
): Request {
const pingedWork = [];
const abortSet: Set<SuspendedWork> = new Set();
Expand All @@ -160,6 +165,7 @@ export function createRequest(
partialBoundaries: [],
onError,
onComplete,
onReadyToStream,
};
// This segment represents the root fallback.
const rootSegment = createPendingSegment(request, 0, null);
Expand Down Expand Up @@ -481,14 +487,17 @@ function finishedWork(
segment: Segment,
) {
if (boundary === null) {
request.pendingRootWork--;
if (segment.parentFlushed) {
invariant(
request.completedRootSegment === null,
'There can only be one root segment. This is a bug in React.',
);
request.completedRootSegment = segment;
}
request.pendingRootWork--;
if (request.pendingRootWork === 0) {
request.onReadyToStream();
}
} else {
boundary.pendingWork--;
if (boundary.forceClientRender) {
Expand Down

0 comments on commit 0509b57

Please sign in to comment.