Back to blogs
Part 3: Debugging React Performance — Measure Before You Optimize

Part 3: Debugging React Performance — Measure Before You Optimize

July 16, 2025

Ashish Gogula Ashish Gogula

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:

  1. Install React DevTools as a Chrome or Firefox extension
  2. Open your app, go to the “Profiler” tab
  3. Click “Record” and interact with your UI
  4. 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:

Blog Image

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:

jsx
console.log('Component X rendered');

Even better, make a custom hook for it:

jsx
function useRenderLog(name) {
  useEffect(() => {
    console.log(`${name} rendered`);
  });
}

Use the hook in your component:

jsx
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

  1. Install the package in your app:
jsx
npm install @welldone-software/why-did-you-render

2. Enable it in development mode (usually in index.js or main.jsx):

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:

jsx
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:

Blog Image

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
Blog Image

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!