Skip to content

refactor: split ReviewState into focused contexts to prevent cascading re-renders #489

@backnotprop

Description

@backnotprop

Problem

ReviewState is a single monolithic context with ~40 dependencies in its useMemo. When ANY state changes, ALL useReviewState() consumers re-render — including panels that don't use the changed data.

During active agent reviews, this causes unnecessary re-renders of diff panels, PR panels, and the sidebar every time job state updates, annotation changes, or search state changes.

Current state

  • jobLogs was split into a separate JobLogsContext (done)
  • PRCommentsTab and PRSummaryTab wrapped in React.memo (done)
  • But every other panel (ReviewDiffPanel, ReviewPRChecksPanel, etc.) still re-renders on any state change

What's in ReviewState today (all in one context)

  • Files & diff: files, focusedFileIndex, diffStyle, diffOverflow, font settings
  • Annotations: allAnnotations, externalAnnotations, selectedAnnotationId, pendingSelection
  • Viewed/staged: viewedFiles, stagedFiles, stagingFile
  • Search: searchQuery, debouncedSearchQuery, activeSearchMatch, etc.
  • AI: aiMessages, isAILoading, aiHistoryForSelection
  • Agent jobs: agentJobs
  • PR: prMetadata, prContext, platformUser
  • Navigation: openDiffFile

Proposed split

Context Data Consumers
DiffContext files, activeFile, diffStyle, search, font Diff panels, file tree
AnnotationContext annotations, selection, editing Sidebar, diff panels
AgentContext jobs, capabilities Agents tab, detail panel
PRContext prMetadata, prContext, platformUser PR panels
JobLogsContext jobLogs Detail panel (already done)

Each context only re-renders its consumers when its specific data changes.

Impact

  • Eliminates cascading re-renders during agent runs
  • Prevents diff panel thrashing when annotations change
  • Prevents PR panel re-renders when search state changes
  • Follows React best practice: split contexts by update frequency (Dan Abramov's "Before You Memo")

Partial mitigations already in place

  • JobLogsContext split (high-frequency SSE logs isolated)
  • React.memo on PRCommentsTab and PRSummaryTab
  • Inline onerror on images (prevents 404 flood even if re-renders happen)

Files involved

  • packages/review-editor/App.tsxreviewStateValue useMemo (the monolith)
  • packages/review-editor/dock/ReviewStateContext.tsx — ReviewState interface
  • All files in packages/review-editor/dock/panels/ — context consumers
  • packages/review-editor/components/ReviewSidebar.tsx — context consumer

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions