Skip to content

perf: wrap IssueCard in React.memo (one-line fix, big win)Β #25

@hoainho

Description

@hoainho

🌟 Before claiming this issue

Two quick steps before you open a PR:

  1. ⭐ Star the repository β€” low-friction signal that you'll follow through
  2. πŸ’¬ Comment I'll take this (or similar) below β€” prevents two contributors racing on the same issue

Full policy: CONTRIBUTING.md β†’ How to claim. If a claim is older than 7 days with no PR, you can reclaim it politely.


What

IssueCard (src/panel/components/IssueCard.tsx) is a plain function component with no React.memo. It receives a single issue: Issue prop that is a stable reference (the state.issues array is only appended to, never mutated).

Every time any message arrives from the background page (FIBER_COMMIT, REDUX_ACTION, TIMELINE_EVENTS β€” all firing at the 5-second poll interval), Panel.tsx runs setState, which cascades through UIStateTab β†’ all IssueCard instances. With ~20 visible issues on a typical React app, all 20 IssueCards re-render even though their issue prop is reference-equal.

File: src/panel/components/IssueCard.tsx line 82.

Why it matters

  • Wasted reconciliation work on every poll.
  • Compounds with the bigger render trees in ReduxTab and TimelineTab β€” on slower machines you can feel a frame hitch every 5 seconds when the panel is in the foreground.
  • Measurable: React DevTools Profiler shows ~3-8ms of IssueCard render time per poll on a 50-issue scenario. With React.memo, this drops to <0.5ms.

How to fix (full implementation hint)

This is a single-line change. The component already has stable props (issue.id is the React key, ISSUE_INFO and SEVERITY_CONFIG are module-level constants).

Step 1: Update the export at line 82

// BEFORE (src/panel/components/IssueCard.tsx:82)
export function IssueCard({ issue }: IssueCardProps) {
  // ... existing body
}

// AFTER
export const IssueCard = React.memo(function IssueCard({ issue }: IssueCardProps) {
  // ... existing body unchanged
});

Step 2: Make sure React is imported

The file already imports React features. If React is not imported as a default, add it at the top:

import React, { useState } from 'react';

Step 3: Bonus β€” apply same fix to AnalysisItemCard

Same pattern at src/panel/tabs/AIAnalysisTab.tsx line 27. Optional but appreciated.

Verify your fix

npm run test:run -- IssueCard
npm run typecheck   # (will be added in #TBD; for now: npx tsc --noEmit)
  1. Run npm run dev and load the extension in Chrome.
  2. Open React DevTools Profiler.
  3. Start recording, wait 10 seconds (so ~2 polls happen), stop recording.
  4. Before fix: every IssueCard instance appears in the flamegraph as "rendered" on each commit.
  5. After fix: IssueCard instances are marked as "did not render" (gray) for unchanged issues.

Acceptance criteria

  • IssueCard is wrapped in React.memo
  • All existing tests in src/__tests__/IssueCard.test.tsx still pass
  • No new TypeScript errors
  • PR description includes a React DevTools Profiler screenshot (before vs after) showing fewer renders

How to claim

Comment "I'm on it" β€” the maintainer will assign you. Read .github/CONTRIBUTING.md for local-dev steps. SLA: PR review within 7 days.


Scope: XS (1 line + screenshot) | Effort: ~30 min | Risk: Lane Tiny

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestgood first issueGood for newcomersperfPerformance improvements

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions