Skip to content

perf(render): memoize PinnedRepos/TopRepos cards and fix stale closure in togglePin#3150

Open
surya0904shankar wants to merge 1 commit into
Priyanshu-byte-coder:mainfrom
surya0904shankar:perf/memoize-pinned-top-repos
Open

perf(render): memoize PinnedRepos/TopRepos cards and fix stale closure in togglePin#3150
surya0904shankar wants to merge 1 commit into
Priyanshu-byte-coder:mainfrom
surya0904shankar:perf/memoize-pinned-top-repos

Conversation

@surya0904shankar

Copy link
Copy Markdown

What Changed

  • Fixed a stale closure bug in togglePin inside src/components/TopRepos.tsx — it previously read pinnedRepos directly from its render closure and was recreated on every render, which could cause it to act on outdated pin data once cards stopped re-rendering unnecessarily (as a result of React.memo).
  • Rewrote togglePin as a useCallback with an empty dependency array, using the functional setPinnedRepos(prev => ...) update form so it always operates on the latest state.
  • Confirmed React.memo (with strict field-by-field comparators) on RepoCard (PinnedRepos.tsx) and RepoItem (TopRepos.tsx), and useMemo on sorting/filtering logic (sortedPinnedRepos, filteredRepos/maxCommits) were already in place and working correctly as required by the issue.

How to Test

  1. Pin and unpin a few repos from the Top Repositories list, confirm the pin state updates correctly and persists.
  2. Pin 3 repos, then try to pin a 4th — confirm the "Maximum 3 pins allowed" error shows.
  3. Open React DevTools → Profiler, record while triggering a repo data refresh (e.g. changing the day-range filter or pinning/unpinning), and confirm only cards whose data actually changed are re-rendered — unaffected cards should be skipped in the flame graph.

Expected result: Pin/unpin behaves correctly under repeated toggles without acting on stale pin state, and repo cards no longer re-render wholesale on every data refresh.


Screenshots / Recordings

Not applicable — this is a performance/behavior fix with no visual UI changes.


Checklist

  • Linked the related issue above
  • Self-reviewed my own diff
  • No unnecessary console.log, debug code, or commented-out blocks
  • npm run lint passes locally (could not verify — ESLint ran out of memory on this machine when linting the full src directory; unrelated to the changed files)
  • No TypeScript errors (npm run type-check) (not run locally — please confirm via CI)
  • Added or updated tests where applicable (no test added; happy to add one for togglePin if requested)
  • Updated documentation / comments if behavior changed (no docs reference this internal function)

Accessibility (UI changes only)

Not applicable — no UI changes in this PR.


Additional Context

Closes #1458

The memoization requirements from the issue (React.memo with a strict comparator on cards, useMemo for sorting) were already implemented in both PinnedRepos.tsx and TopRepos.tsx prior to this PR. While reviewing the memoization logic, I found that togglePin in TopRepos.tsx had a stale-closure bug that the memoization exposed: since cards no longer always re-render, some could hold an outdated togglePin reference capturing stale pinnedRepos state, causing an incorrect pin-limit check or broken rollback on a failed request. This PR fixes that closure bug so the memoization work is fully correct and safe.

@github-actions

github-actions Bot commented Jul 5, 2026

Copy link
Copy Markdown

Thanks for your first PR on DevTrack! 🎉

A maintainer will review it within 48 hours. While you wait:

  • Make sure CI is passing (type-check + lint)
  • Double-check the PR description is filled out and the issue is linked
  • Feel free to ask questions in Discussions if you need help

If you find DevTrack useful, a ⭐ star on the repo is always appreciated — it helps the project grow and attract more contributors!

@github-actions github-actions Bot added gssoc26 GSSoC 2026 contribution type:performance GSSoC type bonus: performance (+15 pts) labels Jul 5, 2026
@github-actions

github-actions Bot commented Jul 5, 2026

Copy link
Copy Markdown

GSSoC Label Checklist 🏷️

@Priyanshu-byte-coder — please apply the appropriate labels before merging:

Difficulty (pick one):

  • level:beginner — 20 pts
  • level:intermediate — 35 pts
  • level:advanced — 55 pts
  • level:critical — 80 pts

Quality (optional):

  • quality:clean — ×1.2 multiplier
  • quality:exceptional — ×1.5 multiplier

Validation (required to score):

  • gssoc:approved — counts for points
  • gssoc:invalid / gssoc:spam / gssoc:ai-slop — does not score

Type labels (type:*) are auto-detected from files and title. Review and adjust if needed.
Points formula: (difficulty × quality_multiplier) + type_bonus

@github-actions github-actions Bot added type:bug GSSoC type bonus: bug fix type:feature GSSoC type bonus: new feature type:design GSSoC type bonus: UI/design (+10 pts) labels Jul 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gssoc26 GSSoC 2026 contribution type:bug GSSoC type bonus: bug fix type:design GSSoC type bonus: UI/design (+10 pts) type:feature GSSoC type bonus: new feature type:performance GSSoC type bonus: performance (+15 pts)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant