R

React Handbook

Clean • Professional

React Profiling & Optimization with DevTools

2 minute

Profiling & Optimization in React

React applications can sometimes experience performance issues due to unnecessary re-renders, heavy components, or inefficient state updates. Profiling helps you identify performance bottlenecks and optimize your React app for faster rendering and better user experience.

React provides React DevTools as a primary tool to profile and optimize React components.

What is React DevTools?

  • A browser extension for Chrome, Firefox, and Edge
  • Provides tools to inspect component hierarchy, props, state, and performance
  • Allows profiling of re-renders, component mount times, and updates
  • Helps detect unnecessary renders and optimize heavy components

Using React DevTools for Profiling

  1. Open React DevTools in your browser
  2. Navigate to the Profiler tab
  3. Click “Record” to capture a session while interacting with your app
  4. Perform actions that trigger re-renders (clicks, typing, scrolling)
  5. Stop recording to view profiling results

Profiler Output Includes:

  • Commit Tree: Shows which components were rendered during each commit
  • Render Duration: Time each component took to render
  • Why did this render: Explains why a component re-rendered (state, props, context, or parent render)

Common Performance Issues

  • Unnecessary re-renders due to parent component updates
  • Heavy computation inside render functions
  • Large lists rendered without virtualization
  • Inefficient state updates causing multiple renders

Optimization Techniques

a) React.memo

Wrap components with React.memo to prevent re-renders when props don’t change

const MyComponent = React.memo(function({ data }) {
  return <div>{data}</div>;
});

b) useCallback

Memoizes functions to prevent passing new function references on every render

const handleClick = useCallback(() => {
  console.log("Clicked!");
}, []);

c) useMemo

Memoizes expensive computations to avoid recalculating on every render

const expensiveValue = useMemo(() => computeHeavyTask(data), [data]);

d) List Virtualization

  • Use React Window or React Virtualized for large lists
  • Only render visible items

e) Lazy Loading & Code Splitting

  • Load components on demand using React.lazy and Suspense
  • Reduces initial bundle size and improves first render performance

Profiling Example

Suppose you have a component tree with multiple child components:

import React, { useState } from "react";

function Child({ value }) {
  console.log("Child rendered");
  return <div>{value}</div>;
}

function Parent() {
  const [count, setCount] = useState(0);
  return (
    <div>
      <Child value="Hello" />
      <button onClick={() => setCount(count + 1)}>Increment</button>
      <p>Count: {count}</p>
    </div>
  );
}

export default Parent;

Problem: Every time you increment count, the Child component also re-renders unnecessarily.

Solution: Wrap Child in React.memo():

const Child = React.memo(({ value }) => {
  console.log("Child rendered");
  return <div>{value}</div>;
});

Now Child only renders if value changes.

Article 0 of 0