Code review example: memo defeated: a fresh callback per render re-renders every row anyway in React
Retired from the DiffDojo practice pool in October 2026; the review below is the canonical answer. An AI wrote this pull request for the task underneath. Read the diff and decide what you would say before you scroll to the review.
The task
Filterable metrics table
- Add a metrics table with a text filter over metric names.
- Clicking a row selects that metric.
- Typing in the filter must re-render only rows whose data changed, row rendering is expensive.
Adds the metrics table with client-side filtering and row selection. Rows are memoized with React.memo so the expensive sparkline cells don't re-render while typing.
The dashboard shows up to 5,000 metrics; each row's Sparkline renders an SVG path from ~200 points.
The diff
src/components/MetricsTable.jsx+40The review
Issue 1: memo defeated: a fresh callback per render re-renders every row anyway
- The memo is real, the benefit is not.
Rowis wrapped inReact.memo, but the parent passesonSelect={(id) => setSelectedId(id)}, a brand-new function on every render. memo compares props by reference, sees a changedonSelect, and re-renders every row. - Typing is the worst case. Each keystroke updates
query, re-renders the parent, and with memo defeated, every visible row re-renders its Sparkline, the exact expensive work the memo was added to avoid. - The fix is smaller than the bug.
setSelectedIdfromuseStatealready has a stable identity: pass it directly. (For anything less convenient,useCallbackdoes the same job.)
The fix: onSelect={setSelectedId}, same behavior, stable identity, memo works.
The fix
{visible.map((metric) => (
<Row
key={metric.id}
metric={metric}
onSelect={setSelectedId}
/>
))}Why it matters
A memo/PureComponent in the tree → check every prop at the call site: "is anything created fresh in this render?" An inline lambda or object literal silently cancels the whole optimization.
Real-world stakes: the dashboard is smooth in the demo with 40 metrics, and typing feels like wading through glue for the customer with 5,000. Nothing errors, profiling is the only witness. AI assistants generate this pairing constantly, they add React.memo as a best practice and inline callbacks as a habit, and the two cancel out.
The verdict
Request changes. memo defeated: a fresh callback per render re-renders every row anyway
Try a live one
React PRs you have not seen the answer to.
Leave inline comments and a verdict, then see what you caught. Free, no signup.
Review a React PR →