Skip to content

Reduce timeline row rerenders#2498

Merged
juliusmarminge merged 1 commit into
mainfrom
cursor/react-performance-scan-29b8
May 6, 2026
Merged

Reduce timeline row rerenders#2498
juliusmarminge merged 1 commit into
mainfrom
cursor/react-performance-scan-29b8

Conversation

@cursor
Copy link
Copy Markdown
Contributor

@cursor cursor Bot commented May 4, 2026

What Changed

  • Split MessagesTimeline context into stable shared state and activity-only state.
  • Extracted row subsections so active turn / working state changes only rerender the controls that depend on them instead of invalidating every visible timeline row.
  • Memoized the row shell to preserve LegendList row identity across activity state changes.

Why

react-doctor and a manual pass pointed to the chat timeline as a hot rendering path. A temporary react-scan harness showed static timeline rows rerendering during active-turn state changes:

  • Before: TimelineRowContent rendered 137 times across the recording.
  • After: TimelineRowContent rendered 43 times across the same recording.

Heavy markdown/code-rendering counts stayed flat, while the activity-sensitive leaf controls continued to update.

UI Changes

No intended visual changes.

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes
  • I included a video for animation/interaction changes

Validation:

  • bun fmt
  • bun lint
  • bun typecheck
  • bun run test src/components/chat/MessagesTimeline.test.tsx
Open in Web View Automation 

Note

Reduce rerenders in timeline rows by splitting shared and activity state into separate contexts

  • Splits TimelineRowSharedState into two contexts in MessagesTimeline.tsx: a stable TimelineRowCtx for view/config props and a new TimelineRowActivityCtx for frequently-changing activity state (active turn, working status, revert state).
  • Extracts TimelineRowContent into focused sub-components (UserTimelineRow, AssistantTimelineRow, ProposedPlanTimelineRow, WorkingTimelineRow) that each consume only the context they need.
  • New leaf components (RevertUserMessageButton, AssistantCompletionDivider, AssistantCopyButton) consume TimelineRowActivityCtx directly, so only they rerender when activity state changes rather than the entire row tree.

Macroscope summarized 6c17b08.


Note

Low Risk
Low risk UI refactor focused on memoization/context splitting; main risk is subtle regressions in per-row controls due to changed component boundaries and context consumption.

Overview
Reduces chat timeline rerenders by splitting the row context into a stable TimelineRowCtx (config/callbacks) and a frequently-changing TimelineRowActivityCtx (active turn/working/revert/completion summary), so activity updates don’t invalidate every visible row.

Refactors TimelineRowContent into memoized, role/kind-specific subcomponents and moves activity-sensitive UI (revert button, completion divider, assistant copy button) to consume the activity context directly, preserving row identity and limiting re-renders to the affected leaf controls.

Reviewed by Cursor Bugbot for commit 6c17b08. Bugbot is set up for automated code reviews on this repo. Configure here.

@github-actions github-actions Bot added size:L 100-499 changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. labels May 4, 2026
@juliusmarminge
Copy link
Copy Markdown
Member

@cursor pls resolve conflcits

@cursor
Copy link
Copy Markdown
Contributor Author

cursor Bot commented May 4, 2026

The PR is now MERGEABLE (no more conflicts). The BLOCKED merge state status is expected — it just means CI or required reviews haven't passed yet, which is unrelated to the conflict resolution.

Resolved the merge conflicts by rebasing the branch onto the latest main. The conflict was in MessagesTimeline.tsx where:

  • Main had extracted TIMELINE_LIST_HEADER / TIMELINE_LIST_FOOTER as module-level constants
  • This PR added the TimelineRowActivityCtx context for the activity-state split

Both changes are now preserved. All checks pass (bun fmt, bun lint, bun typecheck, and the MessagesTimeline.test.tsx tests).

Open in Web Open in Cursor 

Co-authored-by: Julius Marminge <juliusmarminge@users.noreply.github.com>
@cursor cursor Bot force-pushed the cursor/react-performance-scan-29b8 branch from 7bad53f to 6c17b08 Compare May 4, 2026 23:48
@juliusmarminge juliusmarminge marked this pull request as ready for review May 5, 2026 00:07
@macroscopeapp
Copy link
Copy Markdown
Contributor

macroscopeapp Bot commented May 5, 2026

Approvability

Verdict: Approved

Pure React performance optimization that splits context state to reduce rerenders and extracts inline components into named functions. No behavioral changes - same data flows through same rendering logic, just reorganized for better memoization.

You can customize Macroscope's approvability policy. Learn more.

@juliusmarminge juliusmarminge merged commit 536dcad into main May 6, 2026
16 checks passed
@juliusmarminge juliusmarminge deleted the cursor/react-performance-scan-29b8 branch May 6, 2026 03:26
imabdulazeez added a commit to imabdulazeez/t3code that referenced this pull request May 6, 2026
Brings in: server CLI submodule split (pingdotgg#2545), process/trace diagnostics
views (pingdotgg#2532), JetBrains editor support (pingdotgg#2475), MessagesTimeline render
optimizations (pingdotgg#2527, pingdotgg#2498), git/terminal test stabilization (pingdotgg#2540),
keybindings settings editor (pingdotgg#2533), and provider update advisories
(pingdotgg#2312).

Conflict resolutions:
- packages/contracts/src/settings.ts: kept aa's diffFontFamily and
  terminalFontFamily alongside upstream's
  dismissedProviderUpdateNotificationKeys.
- apps/desktop/src/clientPersistence.test.ts: same shape, fixture mirrors
  the schema.
- apps/web/src/components/settings/SettingsPanels.tsx: kept both import
  groups (FontPicker from aa, ProviderUpdateLaunchNotification.logic from
  upstream).
- apps/web/src/localApi.test.ts: extended both fixtures with
  diffFontFamily and terminalFontFamily so the merged ClientSettings
  shape typechecks against the strict desktop bridge contract.

Pre-existing aa typecheck issues fixed at the root so the merge commit
is green:
- apps/desktop/src/electron.d.ts: declaration-merge "local-fonts" into
  Electron's Session.setPermissionRequestHandler permission union (the
  Electron 40 typings omit it even though the runtime supports it).
- apps/web/src/components/DiffPanel.tsx: conditionally spread style on
  Virtualizer instead of passing undefined, satisfying
  exactOptionalPropertyTypes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L 100-499 changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants