Skip to content

Conversation

@SimonEOA
Copy link

@SimonEOA SimonEOA commented Dec 1, 2025

Summary

This PR improves the performance and clarity of the chat message rendering flow by adding proper memoization, refining render-relevant props, and optimizing message-tree update utilities.

Changes

  • Added a custom memo comparison for MessageContent to prevent unnecessary re-renders based on only the props that affect rendering.
  • Wrapped UserMessage and Message in memo and introduced useMemo where appropriate to avoid repeated child rendering.
  • Introduced getMessageRenderProps to ensure stable message-dependent render comparisons.
  • Updated message-tree utility functions to avoid unnecessary array cloning and reduce deep recursion costs.
  • Cleaned up last-assistant-message logic using useMemo for consistent scorable-message detection.

Motivation

  • Fixes/improves issues reported in UI extremely slow for large prompts #2604.
  • Reduces re-renders during streaming, nested updates, and user input changes—resulting in smoother chat performance and more predictable rendering.

Summary by cubic

Optimized chat message rendering with targeted memoization and faster message-tree updates to reduce re-renders and smooth streaming.

  • Refactors
    • Added a custom memo comparison in MessageContent with stable render props.
    • Memoized Message and UserMessage; used useMemo for child content and a shared empty elements array.
    • Memoized last assistant/scorable message detection for consistent scoring.
    • Reworked message-tree utils (add/update/delete/content updates) to avoid unnecessary cloning and deep recursion, returning original arrays when unchanged.

Written for commit 78bbcb1. Summary will update automatically on new commits.

@dosubot dosubot bot added size:L This PR changes 100-499 lines, ignoring generated files. frontend Pertains to the frontend. labels Dec 1, 2025
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 5 files

Prompt for AI agents (all 2 issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="frontend/src/components/chat/Messages/Message/index.tsx">

<violation number="1" location="frontend/src/components/chat/Messages/Message/index.tsx:92">
P1: `useMemo` is called inside the conditional user-message branch, violating React’s hook rules because hooks must run unconditionally and in the same order every render. Move the memoized JSX computation to the top level (e.g., assign it to a variable with useMemo before the return) and reference that variable inside the conditional instead of invoking the hook there.</violation>
</file>

<file name="frontend/src/components/chat/Messages/Message/Content/index.tsx">

<violation number="1" location="frontend/src/components/chat/Messages/Message/Content/index.tsx:130">
P2: `sections` prop changes are ignored by the new memo comparator, so toggling which sections render no longer updates the UI.</violation>
</file>

Since this is your first cubic review, here's how it works:

  • cubic automatically reviews your code and comments on bugs and improvements
  • Teach cubic by replying to its comments. cubic learns from your replies and gets better over time
  • Ask questions if you need clarification on any suggestion

Reply to cubic to teach it or ask questions. Re-run a review with @cubic-dev-ai review this PR

allowHtml={allowHtml}
latex={latex}
/>
{useMemo(
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Dec 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: useMemo is called inside the conditional user-message branch, violating React’s hook rules because hooks must run unconditionally and in the same order every render. Move the memoized JSX computation to the top level (e.g., assign it to a variable with useMemo before the return) and reference that variable inside the conditional instead of invoking the hook there.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At frontend/src/components/chat/Messages/Message/index.tsx, line 92:

<comment>`useMemo` is called inside the conditional user-message branch, violating React’s hook rules because hooks must run unconditionally and in the same order every render. Move the memoized JSX computation to the top level (e.g., assign it to a variable with useMemo before the return) and reference that variable inside the conditional instead of invoking the hook there.</comment>

<file context>
@@ -87,12 +89,17 @@ const Message = memo(
-                      allowHtml={allowHtml}
-                      latex={latex}
-                    /&gt;
+                    {useMemo(
+                      () =&gt; (
+                        &lt;MessageContent
</file context>

✅ Addressed in 78bbcb1

return (
prevProps.allowHtml === nextProps.allowHtml &&
prevProps.latex === nextProps.latex &&
prevProps.elements === nextProps.elements &&
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Dec 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: sections prop changes are ignored by the new memo comparator, so toggling which sections render no longer updates the UI.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At frontend/src/components/chat/Messages/Message/Content/index.tsx, line 130:

<comment>`sections` prop changes are ignored by the new memo comparator, so toggling which sections render no longer updates the UI.</comment>

<file context>
@@ -111,7 +122,18 @@ const MessageContent = memo(
+    return (
+      prevProps.allowHtml === nextProps.allowHtml &amp;&amp;
+      prevProps.latex === nextProps.latex &amp;&amp;
+      prevProps.elements === nextProps.elements &amp;&amp;
+      isEqual(
+        getMessageRenderProps(prevProps.message),
</file context>
Suggested change
prevProps.elements === nextProps.elements &&
prevProps.elements === nextProps.elements &&
isEqual(
prevProps.sections ?? ['input', 'output'],
nextProps.sections ?? ['input', 'output']
) &&

✅ Addressed in 78bbcb1

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 5 files

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

frontend Pertains to the frontend. size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants