perf(site): memo-wrap SmoothedResponse and ReasoningDisclosure to skip completed blocks during streaming (#23674)

During streaming, StreamingOutput's compiler cache guard misses
every chunk because streamState.blocks and streamTools are new
references. This causes renderBlockList to recreate all child JSX
elements, and React calls every child function even for blocks
that finished streaming.

Wrapping SmoothedResponse and ReasoningDisclosure in React.memo
lets React skip the function call entirely when props are stable.
For N completed response blocks and M completed thinking blocks,
this reduces per-chunk function calls from N+M+1 to 1. The
compiler still compiles both inner functions cleanly (6 and 12
cache slots respectively, zero diagnostics).
This commit is contained in:
Mathias Fredriksson
2026-03-26 16:35:12 +00:00
committed by GitHub
parent 081d91982a
commit cc4cca90fd
@@ -48,12 +48,12 @@ import type {
StreamState,
} from "./types";
const ReasoningDisclosure: FC<{
const ReasoningDisclosure = memo<{
id: string;
text: string;
isStreaming?: boolean;
urlTransform?: UrlTransform;
}> = ({ id, text, isStreaming = false, urlTransform }) => {
}>(({ id, text, isStreaming = false, urlTransform }) => {
const { visibleText } = useSmoothStreamingText({
fullText: text,
isStreaming,
@@ -86,7 +86,7 @@ const ReasoningDisclosure: FC<{
</div>
</div>
);
};
});
// Shared block renderer used by both ChatMessageItem (historical
// messages) and StreamingOutput (live stream). Encapsulates the
@@ -107,11 +107,11 @@ type RenderBlockListParams = {
// Wrapper that runs the smooth-streaming jitter buffer on a single
// response block. Only used during live streaming — historical
// messages render through <Response> directly.
const SmoothedResponse: FC<{
const SmoothedResponse = memo<{
text: string;
streamKey: string;
urlTransform?: UrlTransform;
}> = ({ text, streamKey, urlTransform }) => {
}>(({ text, streamKey, urlTransform }) => {
const { visibleText } = useSmoothStreamingText({
fullText: text,
isStreaming: true,
@@ -123,7 +123,7 @@ const SmoothedResponse: FC<{
{visibleText}
</Response>
);
};
});
const InlineTextAttachmentButton: FC<{
content: string;