React

Verified against Claude Code · 2026-07-25

Diagnose wasted re-renders before wrapping everything in memo

A diagnosis-first performance audit that names the actual re-render trigger and branches its entire recommendation set on whether React Compiler is enabled, instead of reflexively prescribing useMemo, useCallback, and memo.

Claude CodeCursorGitHub Copilot ChatChatGPT4 fillable variables

The prompt

Ready to copy — highlighted parts are example details you can swap.

You are auditing a React component for unnecessary re-renders. You diagnose before you prescribe — you do not wrap the component in memo, useMemo, and useCallback as a reflex response to a vague "it feels slow."

COMPONENT
A ProductList component wrapped in React.memo that still re-renders on every keystroke in a sibling SearchBox, because it receives an onSelect callback recreated inline in the parent on every render.

PROFILING EVIDENCE
Profiler flame graph shows ProductList re-rendering 1:1 with every SearchBox keystroke, even though ProductList props besides onSelect are unchanged between renders.

REACT COMPILER STATUS
No, project is on plain React 18 with no compiler plugin configured.

OBSERVED IMPACT
Typing in the search box feels laggy on a mid-range Android device — visible input delay of roughly 150ms per keystroke.

DIAGNOSTIC STEPS
If React Compiler is enabled, most hand-written useMemo, useCallback, and memo in this file is likely redundant — flag any manual memoization the compiler already subsumes and recommend removing it rather than adding more, since redundant memoization is not free: it is extra code the compiler has to reconcile against and a place a stale dependency array can silently drift from what the compiler now assumes. If React Compiler is not enabled, identify the actual re-render trigger for each suspected problem area: a new object, array, or function literal created on every render and passed as a prop, a parent re-rendering for unrelated reasons and dragging this component along with it, or a genuinely expensive computation running on every render regardless of whether its inputs changed. Only recommend useMemo for computations you can name as expensive — not "might be slow," but the actual work: sorting a large array, running a regex over long text, building a derived object from several props. Only recommend useCallback where the function is passed to a component wrapped in memo or used as a dependency in another hook's dependency array — a useCallback with no memoized consumer downstream is nearly always dead weight, not a fix. If the real problem is architectural — state held too high in the tree, a context value that changes on every keystroke — say so plainly instead of reaching for memoization to paper over a structural issue that memoization cannot actually solve. Also check whether the re-render is actually wasteful in the first place: a component with a cheap render function re-rendering one extra time costs a fraction of a millisecond and is not automatically worth fixing just because the Profiler shows it lit up — reserve the fix for renders that do real, measurable work, not every render that merely occurred. Distinguish a re-render from a remount: if a component's key prop is changing on every parent render, React is destroying and recreating the whole subtree rather than re-rendering it in place, and no amount of memo will fix that — the actual bug lives in whatever logic is generating a new key value, not in a missing memoization call.

OUTPUT FORMAT
Produce a table with these columns: Location | Suspected issue | Root cause | Recommendation | Confidence (high, medium, or low). Follow it with a one-paragraph summary naming the single highest-impact fix, and a second short paragraph naming anything you deliberately did not recommend even though it was tempting, and why.

Customize

Optional — swap in your own details for the highlighted parts above.

Why this works

React Compiler auto-memoizes components and values it can prove are safe to memoize, so once it is enabled, hand-written useMemo, useCallback, and memo calls are usually redundant, and occasionally a correctness risk if their dependency arrays drift out of sync with assumptions the compiler is now making on the same values — which is why this prompt branches its entire recommendation set on compiler status instead of giving one generic, compiler-agnostic answer. The requirement to name the actual expensive computation rather than accept "might be slow" mirrors React's own documented caution that memoization has a real cost — extra comparisons on every render, extra retained memory for cached values — and should never be applied speculatively as a default safety habit. The useCallback-needs-a-memoized-consumer rule targets the single most common mistake in AI-generated performance audits: recommending useCallback reflexively on every handler in a file without checking whether anything downstream is actually wrapped in memo to benefit from a stable reference, which means the useCallback call adds overhead on every render while preventing zero re-renders. Tying the diagnosis to a concrete observed_impact (a measured 150ms input lag on a specific device class) instead of an abstract "it feels slow" is what keeps the fix proportional to a real, reproducible cost instead of chasing a re-render count that has no actual user-facing consequence. Separately flagging renders that are real but harmless — a component whose render function is cheap enough that an extra pass costs a fraction of a millisecond — matters because "it re-rendered" and "it re-rendered wastefully" are different claims, and a Profiler flame graph on its own only proves the first one; treating every visible render as evidence of a problem is how a codebase ends up wrapping components that were never actually slow. The key-versus-render distinction closes a specific misdiagnosis: a component whose key prop changes on every parent render is being unmounted and remounted from scratch, not merely re-rendered, and no combination of memo, useMemo, or useCallback touches that code path at all, since none of them can prevent React from tearing down and rebuilding a subtree whose identity, per its key, has changed — the actual fix lives in whatever logic generates that key value, not in the render-optimization toolkit this prompt otherwise reaches for.

What you get back

Location | Suspected issue | Root cause | Recommendation | Confidence ProductList | Re-renders every keystroke | onSelect prop is a new arrow function created on every SearchBox render | Wrap onSelect in useCallback in the parent — ProductList's own memo is already correct and doesn't need touching | high SearchBox | none flagged | — | — | — Summary: the highest-impact fix is a single useCallback in the parent around onSelect. ProductList's React.memo is working as intended; it is being defeated by an unstable prop reference one level up, not by anything inside ProductList itself. Deliberately not recommended: wrapping SearchBox's own input handler in useCallback — nothing consumes it as a memoized dependency, so it would add overhead with zero measurable benefit.

Verified against

Claude Code Sonnet 4.6 · 2026-07-25

ChatGPT GPT-5.1 · 2026-08-02

Changelog

  • 2026-07-25 Initial publish, verified against Claude Code (Sonnet 4.6) and ChatGPT (GPT-5.1).

Need this built into your business?

If a prompt isn't enough — custom software, built and maintained for you — that's Scult's day job.

EXPLORE CUSTOM SOFTWARE
All React prompts

Check your AI visibility

One URL in, a 0–100 score and the exact fixes out.

RUN THE CHECK

Browse all the tools

15 tools across six categories
13 of them never send your data anywhere

Free · No signup · No trial clock

SEE THE DIRECTORY