React DevTools Profiler: Find and Fix Re-renders in 5 Minutes
Most React performance problems are caused by unnecessary re-renders. Learn to use the React DevTools Profiler to identify and eliminate them quickly.
Your React app feels sluggish. Typing in an input field has visible lag. Switching tabs takes 300ms. You suspect re-renders, but guessing which component is the culprit wastes hours. The React DevTools Profiler can pinpoint the exact problem in under five minutes.
Setting Up the Profiler
Install the React DevTools browser extension if you haven't already. Open your app, go to the Profiler tab in DevTools, and click the record button (blue circle). Perform the interaction that feels slow — click a button, type in a field, open a modal — then stop recording.
You'll see a flame chart showing every component that rendered during your interaction. The wider a bar, the longer it took to render. Components highlighted in yellow or red are your targets.
Reading the Flame Chart
Each bar represents a component render. Click on any bar to see:
- Why did this render? — props changed, state changed, or parent rendered
- Render duration — how long this specific component took
- Commit information — total time for the entire render cycle
Enable "Record why each component rendered" in Profiler settings. This is the single most useful feature — it tells you exactly which prop or state change triggered each render.
Common Pattern: Unstable References
The most frequent cause of unnecessary re-renders is creating new object or function references on every render. Here's a classic example and its fix:
// ❌ BAD: New object reference every render
function UserList({ users }: { users: User[] }) {
return (
<div>
{users.map(user => (
<UserCard
key={user.id}
user={user}
style={{ marginBottom: 16 }} // New object every render!
onSelect={() => selectUser(user.id)} // New function every render!
/>
))}
</div>
);
}
// ✅ GOOD: Stable references
const cardStyle = { marginBottom: 16 };
function UserList({ users }: { users: User[] }) {
const handleSelect = useCallback((id: string) => {
selectUser(id);
}, []);
return (
<div>
{users.map(user => (
<UserCard
key={user.id}
user={user}
style={cardStyle}
onSelect={() => handleSelect(user.id)}
/>
))}
</div>
);
}
Common Pattern: Context Over-Subscription
When you put frequently-changing values in React Context, every consumer re-renders on every change — even if they only read a stable part of the context. The fix is to split your contexts:
// ❌ BAD: One context with mixed update frequencies
const AppContext = createContext<{
user: User; // Changes rarely
theme: Theme; // Changes rarely
notifications: Notification[]; // Changes every few seconds
}>();
// ✅ GOOD: Separate contexts by update frequency
const UserContext = createContext<User>();
const ThemeContext = createContext<Theme>();
const NotificationContext = createContext<Notification[]>();
// Components reading only user/theme won't re-render
// when notifications update
The useMemo / React.memo Decision Framework
Don't wrap everything in React.memo — it has its own cost (shallow comparison on every render). Use it when:
- The component renders frequently due to parent re-renders
- The component's own rendering is expensive (large lists, complex DOM)
- The component receives the same props most of the time
Skip it for simple components (buttons, labels) — the memo overhead exceeds the render cost.
Quick Profiler Workflow
- Open Profiler, enable "Record why each component rendered"
- Record the slow interaction
- Sort the flame chart by render duration (click the ranked chart icon)
- Click the slowest component — check why it rendered
- If "parent rendered" — consider
React.memo - If "props changed" — check for unstable references
- If "state changed" — verify the state change is necessary
- Fix, re-profile, confirm improvement
Takeaways
- The Profiler's "why did this render" feature is your most powerful diagnostic tool
- Unstable object/function references cause the majority of unnecessary re-renders
- Split contexts by update frequency to prevent cascade re-renders
- Use
React.memoselectively — only on expensive components with stable props - Profile first, optimize second — never guess at performance problems
Admin
Cal.com
Open source scheduling — tự host booking system, thay thế Calendly. Free & privacy-first.
Bình luận (0)
Đăng nhập để bình luận
Chưa có bình luận nào. Hãy là người đầu tiên!