agentleFS
jayeshsojitra103jayeshsojitra103/claude-frontend-skills/skills/react-performance-audit/SKILL.md

react-performance-audit

Skill0 starsChanged 3 months agoMITView on GitHub

Audit React and Next.js codebases for wasted re-renders, bundle bloat, and Core Web Vitals regressions, then produce a prioritized fix list with measured impact. Use this skill whenever the user mentions slow renders, laggy typing or scrolling, large bundles, LCP/INP/CLS problems, Lighthouse scores, React DevTools Profiler output, memo/useMemo/useCallback decisions, or says something is "janky", "slow", or "re-rendering too much" — including when they just paste a component and ask why it feels slow.

The file

We split this skill into the rules it gives an agent

8 rules. About 0 are common, 5 are distinctive, and 3 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈5

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 3

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Before reading any code, get the symptom and the number.

    line 14
  2. Very specific:

    If the user has no measurement, provide one before diagnosing: a Lighthouse run, a React DevTools Profiler recording, or npx …

    line 23
  3. Distinctive:

    Run the bundled scanner over the source to collect candidate issues fast:

    line 29
  4. Distinctive:

    Treat its output as leads, not verdicts.

    line 40
  5. Very specific:

    Bundle weight: Check for moment, full lodash, unshaken icon packs, and duplicated transitive dependencies.

    line 77
  6. Distinctive:

    Use this structure so the reader can act without reading everything:

    line 87
  7. Distinctive:

    Every fix needs a before/after number from the same measurement used in Step 0.

    line 119
  8. Very specific:

    Do not recommend wrapping everything in memo, do not suggest useCallback for handlers passed to plain DOM elements, and do not present a …

    line 129

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

React Performance Audit

Performance work goes wrong in two directions: optimizing what was never slow, and sprinkling useMemo until the code is unreadable and no faster. This skill enforces the measure → diagnose → fix → verify loop, and refuses to skip the first step.

Step 0 — Establish what "slow" means here

Before reading any code, get the symptom and the number. Ask which of these it is, because each has a different root cause family:

  • Slow initial load → bundle size, server response, render-blocking resources → LCP
  • Slow interaction / laggy typing → re-render cost, long tasks on the main thread → INP
  • Layout shifting while loading → missing dimensions, late-injected content → CLS
  • Slow list scrolling → per-row render cost, missing virtualization
  • Slow navigation between routes → unsplit bundles, waterfall data fetching

If the user has no measurement, provide one before diagnosing: a Lighthouse run, a React DevTools Profiler recording, or npx source-map-explorer on the build output. An audit without a baseline cannot demonstrate improvement and usually optimizes the wrong thing.

Step 1 — Static scan

Run the bundled scanner over the source to collect candidate issues fast:

node scripts/perf_scan.mjs <src-dir>

It flags high-signal patterns: inline object and arrow props passed to memoized children, array index keys, useEffect with a missing or over-broad dependency array, state that should be derived, context values constructed inline, heavy top-level imports, and useState holding values that never trigger a render.

Treat its output as leads, not verdicts. The scanner cannot see how often a component renders or how expensive that render is, and a flagged pattern in a component that renders twice a session is not a problem worth a PR.

Step 2 — Diagnose against the real cost model

React re-renders a component when its state changes, its context value changes, or its parent re-renders. The last one is the source of most confusion — a parent re-render re-renders all children regardless of whether their props changed, unless the child is memoized and its props are referentially stable.

Work through these in order of typical impact:

Context that changes too often. A context whose value is a fresh object every render invalidates every consumer in the tree. Split contexts by update frequency — a stable dispatch-like context and a volatile state context — and memoize the value. This single fix routinely removes more wasted renders than every React.memo in a codebase.

Uncontrolled subtree re-renders. Lifting state higher than needed makes the whole tree re-render on every keystroke. Push state down to the smallest component that owns it, or move the expensive siblings into children so they keep the same element identity across parent renders.

Memoization that does nothing. React.memo on a component receiving style={{...}} or onClick={() => ...} compares a new reference every time and always re-renders, having added a comparison cost for no benefit. Either stabilize the props or drop the memo.

Over-memoization. useMemo on a cheap computation costs a dependency comparison plus retained memory to save a few microseconds. Reserve it for expensive derivations, large list transforms, and referential stability that something downstream actually depends on. With the React Compiler enabled, most manual memoization becomes redundant — check for it before adding more.

Expensive renders rather than frequent ones. Long lists without virtualization, chart libraries rendering thousands of DOM nodes, date formatting inside a map. Fix the cost per render, not the count.

Bundle weight. Check for moment, full lodash, unshaken icon packs, and duplicated transitive dependencies. Route-level React.lazy and dynamic import() for anything below the fold; next/dynamic with ssr: false for browser-only widgets.

Data waterfalls. A component fetching, then rendering a child that fetches, serializes round trips. Hoist to a parallel fetch, or in the App Router move the fetch into a Server Component and stream with Suspense.

Step 3 — Report

Use this structure so the reader can act without reading everything:

## Summary
One paragraph: what's slow, why, expected gain from the top three fixes.

## Baseline
| Metric | Current | Target |
|---|---|---|
| LCP / INP / CLS / bundle (gzip) | | |

## Findings
### 1. <Title> — Impact: High | Effort: Low
**Where:** `src/path/File.tsx:42`
**What happens:** the mechanism, in terms of React's render model
**Evidence:** profiler number, bundle bytes, or scanner hit
**Fix:** minimal diff
**Expected gain:** quantified, with the assumption stated

## Not worth fixing
Patterns that look wrong but cost nothing here — with the reason. This section keeps the
team from "fixing" things later and reintroducing complexity.

## Verification
The exact command or profiling step that confirms each fix landed.

Order findings by impact-to-effort, never by file order. Cap the list at the eight that matter; a 40-item audit is ignored.

Step 4 — Verify and prevent

Every fix needs a before/after number from the same measurement used in Step 0. Then close the loop so the regression cannot silently return:

  • Bundle budget in CI (size-limit or @next/bundle-analyzer with a threshold that fails)
  • Lighthouse CI on preview deployments with asserted budgets
  • Real-user monitoring via web-vitals reporting INP and LCP at p75, since lab numbers on fast hardware hide the problem that users actually have

Anti-patterns to avoid in your own recommendations

Do not recommend wrapping everything in memo, do not suggest useCallback for handlers passed to plain DOM elements, and do not present a micro-optimization as a headline fix when a 400 KB dependency is sitting in the entry chunk. Credibility in a performance review comes from correct prioritization more than from knowing obscure APIs.

For the mechanics of profiling — Profiler flame chart reading, why-did-you-render setup, Chrome performance traces, and INP attribution — see references/measuring.md.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.