React Profiler

Measure rendering performance of your components

📊 What is the Profiler?

The Profiler measures how often components render and the cost of rendering. It helps identify performance bottlenecks by tracking render times, allowing you to optimize slow components and improve app performance.


<Profiler id="App" onRender={callback}>
  <App />
</Profiler>
                                    

Key Concepts

⏱️

Render Time

Measure component render duration

🔍

Performance

Identify slow components

📈

Metrics

Track rendering statistics

🎯

Optimization

Find areas to improve

🔹 Basic Profiler Usage

Wrap components with Profiler to measure their performance. The onRender callback receives detailed metrics about each render, including timing information and what caused the update.

import { Profiler } from 'react';

function onRenderCallback(
  id,           // Profiler id
  phase,        // "mount" or "update"
  actualDuration, // Time spent rendering
  baseDuration,   // Estimated time without memoization
  startTime,      // When render started
  commitTime,     // When React committed
  interactions    // Set of interactions
) {
  console.log(`${id} took ${actualDuration}ms to render`);
}

function App() {
  return (
    <Profiler id="App" onRender={onRenderCallback}>
      <Dashboard />
    </Profiler>
  );
}

Console Output:

App took 12.5ms to render

🔹 Multiple Profilers

Use multiple Profilers to measure different parts of your app independently. This helps pinpoint exactly which sections are slow and need optimization.

import { Profiler } from 'react';

function App() {
  return (
    <div>
      {/* Profile header separately */}
      <Profiler id="Header" onRender={onRenderCallback}>
        <Header />
      </Profiler>

      {/* Profile sidebar separately */}
      <Profiler id="Sidebar" onRender={onRenderCallback}>
        <Sidebar />
      </Profiler>

      {/* Profile main content separately */}
      <Profiler id="Content" onRender={onRenderCallback}>
        <MainContent />
      </Profiler>
    </div>
  );
}

Console Output:

Header took 3.2ms to render
Sidebar took 8.7ms to render
Content took 15.3ms to render

🔹 Tracking Render Phases

Distinguish between mount and update phases to understand component behavior:

import { Profiler } from 'react';

function onRenderCallback(id, phase, actualDuration) {
  if (phase === 'mount') {
    console.log(`${id} mounted in ${actualDuration}ms`);
  } else {
    console.log(`${id} updated in ${actualDuration}ms`);
  }
}

function UserProfile() {
  return (
    <Profiler id="UserProfile" onRender={onRenderCallback}>
      <div>
        <h2>User Profile</h2>
        <UserDetails />
      </div>
    </Profiler>
  );
}

Console Output:

UserProfile mounted in 10.2ms
UserProfile updated in 3.5ms

🔹 Performance Logging

Create a utility to log and analyze performance data:

import { Profiler } from 'react';

// Performance logger utility
const performanceLogger = (id, phase, actualDuration) => {
  // Only log in development
  if (process.env.NODE_ENV === 'development') {
    const color = actualDuration > 10 ? '🔴' : '🟢';
    console.log(
      `${color} ${id} (${phase}): ${actualDuration.toFixed(2)}ms`
    );
  }
};

function App() {
  return (
    <Profiler id="App" onRender={performanceLogger}>
      <ExpensiveComponent />
    </Profiler>
  );
}

🔹 Nested Profilers

Nest Profilers to measure component hierarchies and understand parent-child rendering relationships:

import { Profiler } from 'react';

function App() {
  return (
    <Profiler id="App" onRender={onRenderCallback}>
      <div>
        <h1>Dashboard</h1>
        
        {/* Nested profiler for specific component */}
        <Profiler id="DataTable" onRender={onRenderCallback}>
          <DataTable />
        </Profiler>
      </div>
    </Profiler>
  );
}

🔹 Real-World Example

Complete example with performance tracking:

import { Profiler, useState } from 'react';

function App() {
  const [count, setCount] = useState(0);

  const handleRender = (id, phase, actualDuration) => {
    console.log({
      component: id,
      phase: phase,
      renderTime: `${actualDuration.toFixed(2)}ms`,
      timestamp: new Date().toISOString()
    });
  };

  return (
    <Profiler id="Counter" onRender={handleRender}>
      <div>
        <h1>Count: {count}</h1>
        <button onClick={() => setCount(count + 1)}>
          Increment
        </button>
      </div>
    </Profiler>
  );
}

🔹 Best Practices

✅ Do:

  • Use in development to find bottlenecks
  • Profile specific slow components
  • Compare before/after optimization
  • Remove Profilers in production

❌ Don't:

  • Leave Profilers in production code
  • Profile every single component
  • Ignore the performance data
  • Optimize without measuring first

🧠 Test Your Knowledge

What does the Profiler measure?