Performance
React performance work is mostly measuring before changing - the Profiler and DevTools tell you the truth that intuition gets wrong.
React performance toolkit
EXAMPLE
// 1. Measure with React DevTools Profiler
// In dev: open DevTools -> Profiler -> Record -> interact -> stop
// Read the flamegraph: which component re-rendered, why, how long
// 2. The actual rules
// - The default React renders a lot; that is OK
// - Only optimise the components you measured as slow
// - Premature memo and useMemo hurt readability and rarely help
// 3. Stable references - when memo actually pays off
import { memo, useCallback, useMemo } from 'react';
const Row = memo(function Row({ user, onSelect }: { user: User; onSelect: (id: string) => void }) {
return <li onClick={() => onSelect(user.id)}>{user.name}</li>;
});
function List({ users }: { users: User[] }) {
const onSelect = useCallback((id: string) => {
/* ... */
}, []);
return <ul>{users.map((u) => <Row key={u.id} user={u} onSelect={onSelect} />)}</ul>;
}
// 4. Virtualise long lists
// npm install @tanstack/react-virtual
import { useVirtualizer } from '@tanstack/react-virtual';
function BigList({ items }: { items: any[] }) {
const parentRef = useRef<HTMLDivElement>(null);
const v = useVirtualizer({
count: items.length,
getScrollElement: () => parentRef.current,
estimateSize: () => 40,
});
return (
<div ref={parentRef} style={{ height: 600, overflow: 'auto' }}>
<div style={{ height: v.getTotalSize(), position: 'relative' }}>
{v.getVirtualItems().map((row) => (
<div key={row.index} style={{ position: 'absolute', top: row.start, height: 40 }}>
{items[row.index].name}
</div>
))}
</div>
</div>
);
}
// 5. Code split route components
const Settings = React.lazy(() => import('./Settings'));
// Wrap in <Suspense fallback={<Spinner />}>
// 6. Avoid unnecessary state in parents
// Move state down to leaves - small re-renders are cheap; big subtree re-renders are not.
// 7. React Compiler (RFC, stabilising) auto-memoises code
// Once stable, remove most useCallback/useMemo and let the compiler do the work.
// 8. Network is usually the bottleneck, not rendering
// - Cache with TanStack Query / SWR
// - Suspend on data fetching, not on UI
// - Reduce payloads server-side before reaching for React tricks
Why it matters
Measure first. The Profiler is right; your intuition is wrong. Most React perf wins come from virtualisation, code splitting, and smarter data fetching - not from sprinkling useMemo everywhere.
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Example
Example
// Profile with React DevTools. Wrap pure rows in React.memo. // Use stable callbacks (useCallback) when passed to memoised children.Try it Yourself »
Discussion
Loading…