
Part 3: Debugging React Performance — Measure Before You Optimize
Published: 7/16/2025
Before you dive into optimizing React, let’s be honest — most performance problems come from guessing what’s slow instead of measuring it.
In this final part of the series, we’ll walk through how to actually see what's happening under the hood of your app, using tools like React DevTools Profiler and why-did-you-render
But first — if you haven’t read the earlier parts of this series, I recommend starting there:
Part 1: React Rendering Demystified — What Actually Causes Re-Renders
Part 2: Optimizing React Re-renders — Memoization and Smarter Components
Both will give you the context you need to understand why your app might be rendering more than it should.
Table of Contents
- Why measuring matters more than guessing
- Using React DevTools Profiler
- Adding console logs smartly
- Tracking renders with why-did-you-render
- Finding real bottlenecks
- Debugging async & network-triggered re-renders
- Key Takeaways
Why Measuring Matters More Than Guessing
It’s tempting to wrap everything in React.memo or use useCallback everywhere — but unless you actually know what’s slow, you might just add complexity without any gain.
React is already fast. Your job is to find out:
- Which components render too often
- Which renders are actually expensive
- And why they’re happening in the first place
That’s where the right tools come in.
React DevTools Profiler — Your First Stop
React DevTools comes with a Profiler tab that tells you exactly:
- Which components rendered
- How long each render took
- What triggered those renders (state, props, context, etc.)
How to use it:
- Install React DevTools as a Chrome or Firefox extension
- Open your app, go to the “Profiler” tab
- Click “Record” and interact with your UI
- Once you stop recording, you'll be presented with a visualization of your component updates. The Profiler offers different views, and for your first stop, the 'Ranked' view is incredibly useful.
You’ll see which components took the longest to render and how often they re-rendered.
💡 Look for:
- Components that render frequently
- Components that take longer than 1–2ms to render
- Re-renders triggered by unchanged props or context
Here's a sample from my own app:

This image shows the React DevTools Profiler in action, specifically highlighting the "Ranked" view. This view is your first stop because it lists components by how long they took to render, making it easy to spot potential bottlenecks.
In the yellow-orange bar at the top of the Profiler, you'll see a count like 1 / 18. This tells us we're looking at the 1st render out of a total of 18 times our components updated during this recording session. Seeing a high number of renders can be an immediate flag that your app might be re-rendering more often than necessary!
On the left, you see horizontal bars representing your components, with their render times in milliseconds (e.g., DataRouter (Memo) 0.9ms). Longer bars and higher ms values indicate components that are taking more time.
The right sidebar provides insights like the total render duration for this update (Render: 7.1ms) and, crucially, "What caused this update?". This helps you understand why a render happened, which is key to preventing unnecessary re-renders.
Want to go deeper?
Here’s an excellent walkthrough by Kyle Simpson where he explains how to interpret flame graphs and track down slow components visually.
Watch: How To Maximize Performance In Your React Apps
Smart Console Logs — Quick and Dirty Debugging
Sometimes, all you need is a simple log:
console.log('Component X rendered');
Even better, make a custom hook for it:
function useRenderLog(name) {
useEffect(() => {
console.log(`${name} rendered`);
});
}
Use the hook in your component:
function MyComponent() {
useRenderLog("MyComponent");
return <div>Hello</div>;
}
This helps you visually track render frequency without diving into Profiler every time.
Track Renders with why-did-you-render
why-did-you-render is a small dev-only library that logs unnecessary re-renders to your browser’s console.
It watches your components and tells you if something re-rendered without any actual prop changes.
Think of it like a smart assistant whispering:
“Hey, this component re-rendered but nothing really changed. Maybe you can optimize it?”
How it works
- Install the package in your app:
npm install @welldone-software/why-did-you-render
2. Enable it in development mode (usually in index.js or main.jsx):
import React from 'react';
if (process.env.NODE_ENV === 'development') {
const whyDidYouRender = require('@welldone-software/why-did-you-render');
whyDidYouRender(React, {
trackAllPureComponents: true,
});
}
3.Wrap your components in React.memo() to let React skip renders if props haven’t changed:
const MyComponent = React.memo((props) => {
return <div>{props.name}</div>;
});
// Tell WDYR to track this
MyComponent.whyDidYouRender = true;
Now, when MyComponent re-renders without a reason, WDYR will log something like this in the console:
[why-did-you-render] MyComponent re-rendered unnecessarily.
Here’s what it looks like in action:

Want to dive deeper?
Check out the full documentation here: why-did-you-render on GitHub
Find the Real Bottlenecks
Look out for patterns like:
- Parent re-renders triggering all children
- Large lists or heavy UIs without virtualization
- Props or context changing too frequently
- Functions or objects being recreated on every render
Once spotted, you can:
- Wrap expensive components in React.memo
- Use useCallback and useMemo where needed
- Break components down further to isolate updates
Debugging Async or Data-Fetching Re-renders
Sometimes the re-renders are caused by data fetching, not just state changes.
Use the Network tab in DevTools to check if:
- A fetch or API call is being repeated on every render
- A loading spinner or skeleton UI keeps re-rendering
To fix this:
- Use useEffect with proper dependencies
- Store results in state or context to avoid repeat fetches
- Memoize fetched data or paginate large lists
Me watching the profiler record 32 re-renders for no reason

Key Takeaways
- Don’t guess — measure using DevTools, logs, and profiler
- Start with DevTools Profiler for a visual breakdown
- Use why-did-you-render to catch unnecessary updates
- Debug with logs when profiling is overkill
- Optimize only what’s proven to be slow or too frequent
That’s a Wrap!
That’s the end of this 3-part series on React performance.
If you made it this far, you now know:
- Why React re-renders (Part 1)
- How to prevent extra renders with memoization (Part 2)
- And how to measure and fix performance issues with confidence (Part 3)
If you’ve used any of these techniques in your projects, or found a bug the Profiler helped uncover — I’d love to hear about it!