Skip to main content

React Profiler Component

The Profiler component measures the performance of specific parts of your React application. It helps identify performance bottlenecks by tracking how long components take to render.

Basic Usage

Implementation Details

The Profiler uses the REACT_PROFILER_TYPE symbol (see ReactClient.js:13) to identify profiler components in the React tree.

The onRender Callback

The onRender callback receives six parameters providing detailed timing information:

Parameters

id: string

The unique identifier of the Profiler tree that committed. Use this to identify which part of your app was measured if you have multiple Profilers.

phase: “mount” | “update”

Indicates whether the component tree was mounted for the first time or re-rendered due to a prop, state, or hook change.

actualDuration: number

Time in milliseconds spent rendering the Profiler and its descendants for the current update. This indicates how well the subtree uses memoization. Lower is better. A high value might indicate:
  • Components aren’t memoized when they should be
  • Expensive calculations aren’t using useMemo
  • Too many components re-rendering unnecessarily

baseDuration: number

Time in milliseconds estimating how long it would take to render the entire Profiler subtree without any optimizations (without React.memo, useMemo, etc.). Comparison:
  • If actualDuration is much lower than baseDuration, memoization is working well
  • If they’re similar, there’s little benefit from current memoization

startTime: number

Timestamp when React began rendering this update. Can be used to group renders from the same commit.

commitTime: number

Timestamp when React committed this update. Shared among all Profilers in a commit, enabling grouping.

Real-World Usage Patterns

Tracking Component Performance

From ReactProfiler-test.internal.js:287, here’s how to track mount and update performance:
The onRender callback itself should be lightweight. Avoid expensive operations inside it, as they’ll add overhead to your measurements. Consider batching measurements and sending them asynchronously.

Nested Profilers

Profilers can be nested to measure different parts of your app separately:
In this example:
  • The dashboard Profiler measures the entire dashboard including Header and Footer
  • The sidebar and content Profilers provide more granular measurements
  • All will have the same commitTime if they update together

Conditional Profiling

Only profile in development or for specific users:
Profilers add overhead to your application. While the impact is minimal, avoid using them in production unless you’re collecting performance metrics. Always profile in development mode first to identify issues.

Analyzing Performance Data

Collect and analyze performance data over time:

Error Handling

From ReactProfiler-test.internal.js:68, errors thrown in onRender callbacks don’t break the commit phase:
Even though errors in onRender won’t break your app, always handle errors gracefully. This ensures your profiling doesn’t interfere with the user experience.

Commit Phase Timing

From ReactProfiler-test.internal.js:104, the onRender callback is only invoked during the commit phase, not during render:
This means:
  • Measurements reflect completed renders
  • Interrupted renders (via Suspense) won’t trigger callbacks
  • All lifecycle methods have already run

Comparing Performance Over Time

Production Monitoring

For production environments, sample profiling data to reduce overhead:

Best Practices

  • Use specific id props to identify different parts of your app
  • Keep onRender callbacks lightweight
  • Batch analytics calls to reduce network overhead
  • Use nested Profilers for granular measurements
  • Compare actualDuration vs baseDuration to measure memoization effectiveness
  • Don’t use Profilers everywhere in production
  • Avoid heavy computations in onRender callbacks
  • Remember that profiling itself adds small overhead
  • Test with realistic data sizes and user interactions