Common React Performance Mistakes You’re Probably Making in Code Reviews
A no‑fluff guide to the most frequent React performance pitfalls seen in code reviews, with practical fixes and real‑world examples.

Skipping memoization for expensive calculations
It’s tempting to drop a useEffect or just compute a value inline. When that computation touches large arrays or objects, React will re‑run it on every render, killing frame rates.
function ItemList({items}) {
// Bad: runs on every render
const total = items.reduce((sum, i) => sum + i.price, 0);
return <div>Total: {total}</div>;
}Wrap the heavy work in useMemo and list the dependencies correctly.
function ItemList({items}) {
const total = useMemo(() =>
items.reduce((sum, i) => sum + i.price, 0),
[items]
);
return <div>Total: {total}</div>;
}Unnecessary re‑renders caused by object/array props
Passing a freshly created object or array as a prop forces child components to think the reference changed, even if the contents are identical.
function Parent({data}) {
return <Child config={{theme: data.theme}} />; // new object each render
}Lift the constant out of the render or memoize it.
const memoConfig = useMemo(() => ({theme: data.theme}), [data.theme]);
return <Child config={memoConfig} />;Overusing React.memo without proper prop checks
Many teams slap React.memo on every component hoping for a win. If the component receives new object props every time, the memoization is useless and adds an extra shallow compare.
Instead, audit the component: does it actually receive stable primitives? If not, either memoize the props or drop React.memo.
Heavy CSS-in-JS at the top level
Libraries like styled‑components generate a new class string on each render. When you place them in a layout component that re‑renders often, you end up with thousands of style injections per second.
Extract static styles to a separate file or use the as prop with a pre‑generated class name.
Ignoring the cost of large lists
Rendering 1,000 rows in a table sounds fine until the UI stalls on scroll. The fix is simple: virtualize.
import {FixedSizeList as List} from 'react-window';
function LargeTable({rows}) {
return (
<List height={500} itemCount={rows.length} itemSize={35}>
{({index, style}) => (
<div style={style}>Row {rows[index].id}</div>
)}
</List>
);
}Virtualization reduces DOM nodes to only what’s visible, cutting paint time dramatically.
Conclusion
Performance in React isn’t about sprinkling useMemo everywhere; it’s about identifying real work that repeats and breaking the render chain where it hurts. During code reviews, ask yourself: Is this value cheap to compute? Are the props stable? Do we need this many DOM nodes? Answering those three questions will catch most of the mistakes that slip through.