DEV Community

Cover image for How to Find and Fix Slow Components
Muneeb Ansari | BiteGlitz
Muneeb Ansari | BiteGlitz

Posted on

How to Find and Fix Slow Components

A practical guide to measuring React rendering performance, identifying slow components, understanding render causes, and fixing performance problems without premature optimization.

Introduction

A React application can feel slow for many different reasons.

Maybe clicking a button causes a noticeable delay. Maybe typing into a search field feels laggy. Maybe opening a dashboard takes too long. Or perhaps a component takes hundreds of milliseconds to render even though the UI doesn't look particularly complicated.

The difficult part isn't knowing that something is slow.

The difficult part is finding what is actually slow.

This is where the React Profiler becomes useful.

Instead of guessing which component is responsible for a performance problem, you can record an interaction and inspect:

Which components rendered
How long rendering took
Which components rendered repeatedly
Which components were affected by an update
How expensive individual renders were
Whether an optimization actually improved performance

This article walks through a practical workflow for finding slow React components and fixing them.

It is intended for developers who already understand basic React concepts such as components, props, state, and hooks.

Table of Contents
What Is the React Profiler?
Rendering vs DOM Updates
Why Measuring Performance Matters
Setting Up React DevTools
Recording a Performance Profile
Understanding the Profiler Interface
Finding Slow Components
Understanding Render Causes
Example: A Slow Component
Fixing Expensive Calculations
Fixing Unnecessary Child Renders
Optimizing Large Lists
Using the Browser Performance Panel
Measuring Before and After
Best Practices
Common Mistakes
Performance Tips
Security Considerations
Accessibility Considerations
SEO Considerations
Real Project Example
Conclusion
Discussion

  1. What Is the React Profiler?

The React Profiler is a performance analysis tool available through React DevTools.

It helps developers understand how React components behave during rendering.

A simplified workflow looks like this:

User interaction

React update

Components render

Profiler records activity

Developer analyzes expensive work

Targeted optimization

Profile again

The important part is the last step.

Profiling should be an iterative process.

Don't assume that changing code made your application faster. Measure it.

  1. Rendering vs DOM Updates

One of the most important concepts to understand is that a React render doesn't necessarily mean the browser DOM was changed.

Consider:

function UserProfile({ user }) {
return (


{user.name}


{user.email}



);
}

When React renders this component, React calculates what the UI should look like.

It then compares the result with the previous render.

If nothing changed, React may not need to update the actual DOM.

So when profiling React, don't automatically assume:

"This component rendered, therefore the DOM was updated."

Rendering is one stage of React's update process.

  1. Why Measuring Performance Matters

Imagine a dashboard contains:

Dashboard
├── Header
├── Sidebar
├── Search
├── Statistics
├── RevenueChart
├── OrdersTable
└── Notifications

A developer notices that typing into the search box feels slow.

One possible assumption is:

"The search input must be slow."

But the actual problem could be:

Search input

Dashboard state update

RevenueChart renders

OrdersTable renders

Statistics renders

Notifications renders

The search input may be perfectly fine.

The real problem could be that one of the unrelated components performs expensive work every time the search state changes.

Without profiling, you're guessing.

With profiling, you can investigate the actual rendering behavior.

  1. Setting Up React DevTools

React DevTools is available as a browser extension and provides development tools for inspecting React applications.

After installing it, open your React application and open the browser's developer tools.

You should see React-specific panels such as:

Components
Profiler

The exact interface can change between React DevTools versions, so focus on the concepts rather than memorizing a particular UI layout.

Important: Profile your application in a realistic development environment and, when appropriate, validate important findings with a production build. Development behavior can include additional checks and instrumentation.

  1. Recording a Performance Profile

Let's use a simple application.

import { useState } from "react";

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

return (


setCount((value) => value + 1)}>
Count: {count}
  <SlowComponent />
</main>

);
}

The component below intentionally performs expensive work:

function SlowComponent() {
let total = 0;

for (let i = 0; i < 50_000_000; i++) {
total += i;
}

return

Result: {total}

;
}

Every time App renders, SlowComponent renders too.

That means clicking the button can repeatedly execute the expensive loop.

Profile it

A practical workflow is:

Open the application.
Open React DevTools.
Open the Profiler.
Start recording.
Perform the interaction that feels slow.
Stop recording.
Inspect the recorded commit.
Look for expensive components.
Change the code.
Profile the same interaction again.

The important principle is:

Reproduce the same interaction before and after the optimization.

That makes your comparison much more useful.

  1. Understanding the Profiler Interface

The Profiler provides several useful ways to inspect rendering activity.

Depending on the React DevTools version, you'll encounter visualizations such as:

Flamegraph
Ranked view
Commit information
Component render timings

The names and presentation may evolve, but the underlying questions remain the same.

Flamegraph

The flamegraph helps visualize the component tree and rendering work.

You can use it to identify components that take a significant amount of time.

Ranked View

A ranked view is useful when you want to quickly find the components that consumed the most rendering time.

For example:

OrdersTable 120 ms
RevenueChart 82 ms
Statistics 18 ms
Header 2 ms
Footer 1 ms

This immediately gives you a better starting point.

Instead of optimizing Header, investigate OrdersTable.

  1. Finding Slow Components

Suppose your profile shows:

Dashboard 145 ms
OrdersTable 118 ms
SearchBar 3 ms
Header 2 ms
Footer 1 ms

The first place to investigate is OrdersTable.

But don't immediately add React.memo.

First ask:

Why is OrdersTable expensive?

Potential causes include:

Large calculations
Sorting data during render
Filtering thousands of records
Rendering too many DOM nodes
Complex child components
Expensive formatting
Unnecessary state updates
Repeated API transformations

Profiling tells you where the problem is.

Your code inspection determines why it happens.

  1. Understanding Render Causes

Finding a slow component is only half of the job.

You also need to understand why it rendered.

Common reasons include:

State changed
const [count, setCount] = useState(0);

Calling:

setCount((value) => value + 1);

causes the component using that state to update.

Props changed

If user changes, the child may need to render again.

Parent rendered

A child can render when its parent renders, even if the child doesn't have its own state update.

Context changed

Components consuming a changed context value may render again.

Understanding the cause is important because different causes require different solutions.

  1. Example: A Slow Component

Consider this component:

function ProductList({ products, search }) {
const filteredProducts = products
.filter((product) =>
product.name.toLowerCase().includes(search.toLowerCase())
)
.sort((a, b) => a.name.localeCompare(b.name));

return (

    {filteredProducts.map((product) => (
  • {product.name}
  • ))}

);
}

For a list containing 50 items, this may be completely fine.

For 50,000 items, the situation changes.

Every render performs:

Filtering
Sorting
Mapping
Creating many React elements

If the component renders frequently, the work can become expensive.

  1. Fixing Expensive Calculations

One possible optimization is to memoize the derived data.

import { useMemo } from "react";

function ProductList({ products, search }) {
const filteredProducts = useMemo(() => {
const query = search.toLowerCase();

return products
  .filter((product) =>
    product.name.toLowerCase().includes(query)
  )
  .sort((a, b) => a.name.localeCompare(b.name));

}, [products, search]);

return (

    {filteredProducts.map((product) => (
  • {product.name}
  • ))}

);
}

Now React can reuse the calculated value when the dependencies haven't changed.

However, this doesn't automatically make every component faster.

useMemo has its own overhead and should be used when the calculation is expensive enough to justify it.

  1. Fixing Unnecessary Child Renders

Consider:

function Dashboard() {
const [search, setSearch] = useState("");

return (
<>


</>
);
}

If Analytics is expensive and doesn't depend on search, repeatedly rendering it may be wasteful.

You could isolate it:

import { memo } from "react";

const Analytics = memo(function Analytics() {
return (


Analytics


{/* Expensive chart */}

);
});

Now the component can skip rendering when its props remain unchanged.

But again, memo is not a universal performance solution.

If the component receives changing props, it can still render.

For example:

The object is recreated on each render.

A memoized component may therefore still see a changed prop reference.

  1. Optimizing Large Lists

Large lists are a common source of slow rendering.

Consider:

function Users({ users }) {
return (


{users.map((user) => (

))}

);
}

Rendering 20 users is usually easy.

Rendering thousands of complex user cards can be expensive.

In these cases, virtualization can help.

Instead of rendering every item, virtualization renders only the items currently visible to the user.

Conceptually:

10,000 users

Without virtualization:
████████████████████ 10,000 DOM items

With virtualization:
██ 20–50 visible items

This can dramatically reduce initial rendering and scrolling work for very large lists.

  1. Using the Browser Performance Panel

React Profiler isn't the only performance tool.

The browser's Performance panel can help investigate problems outside React itself.

For example:

User click

React render

JavaScript calculation

Layout

Paint

A slow interaction may not be caused entirely by React.

Possible causes include:

Expensive JavaScript
Layout recalculation
Paint operations
Network requests
Image processing
Long tasks

This is why experienced developers use multiple tools instead of assuming every performance problem is a React problem.

  1. Measure Before and After

Suppose your original profile shows:

OrdersTable: 180 ms

You optimize the component and profile again:

OrdersTable: 42 ms

That's useful evidence.

But don't stop there.

Check whether the optimization affected the actual user interaction.

For example:

Before

Search interaction: 230 ms

After

Search interaction: 71 ms

Now you have a stronger signal that the change helped the user experience.

The goal isn't:

"Make the profiler numbers look smaller."

The goal is:

Make real interactions faster.

Best Practices
✅ Do ❌ Don't
Profile before optimizing Guess the bottleneck
Reproduce realistic interactions Test only isolated renders
Fix the largest bottlenecks first Optimize every component
Measure before and after Assume an optimization worked
Investigate the cause Add memo blindly
Check production behavior Rely only on development timings
Consider browser performance too Blame React automatically
Common Mistakes

  1. Adding React.memo Everywhere

Memoization isn't free.

If a component is extremely cheap to render, memoizing it may add unnecessary complexity without meaningful benefits.

  1. Using useMemo for Everything

This:

const result = useMemo(() => a + b, [a, b]);

is usually unnecessary.

The calculation is trivial.

useMemo becomes more interesting when the calculation is genuinely expensive or when referential stability is important for another optimization.

  1. Optimizing Without Profiling

Changing five components because you think they might be slow doesn't give you reliable information.

Profile first.

  1. Only Looking at Render Time

A component can render quickly while the overall interaction remains slow because of:

Network requests
JavaScript execution
Layout
Painting
Third-party scripts

Look at the entire interaction.

  1. Testing Only on a Powerful Computer

A machine with a high-end CPU may hide performance problems.

Test on:

Lower-powered devices
Mobile devices
Realistic datasets
Slower network conditions when relevant
Performance Tips
Keep expensive work out of render

If something can be calculated once or moved outside the rendering path, consider doing so.

Keep state local

Don't make the entire application depend on a state update that only one small component needs.

Avoid rendering huge lists

Use pagination, filtering, or virtualization where appropriate.

Profile real interactions

Measure the things users actually do:

Typing
Searching
Opening menus
Navigating
Filtering
Submitting forms
Don't optimize blindly

Performance work should be evidence-driven.

Security Considerations

Performance optimization doesn't replace security.

When profiling an application:

Don't expose production user data unnecessarily.
Avoid recording sensitive information in shared screenshots or recordings.
Don't place secrets in client-side code while creating performance tests.
Keep development tooling restricted appropriately in production environments.
Be careful when profiling authenticated applications containing private information.

Performance tooling should be treated as a development tool, not a reason to expose application data.

Accessibility Considerations

Performance and accessibility should be optimized together.

For example, replacing a normal button with a custom component might appear faster but accidentally remove keyboard accessibility.

Always preserve:

Semantic HTML
Keyboard navigation
Focus management
Screen-reader information
Accessible form labels
Appropriate loading states

A fast interface that is difficult to use is still a poor interface.

SEO Considerations

Performance can affect how users experience pages and can contribute to better Core Web Vitals.

When optimizing React applications:

Avoid unnecessary JavaScript.
Lazy-load code that isn't immediately needed.
Optimize images.
Reduce expensive client-side rendering where appropriate.
Use server rendering or static rendering when it makes sense for the application.
Keep important content accessible to search engines.

Don't optimize purely for an SEO score, though.

A good optimization should improve the experience for real users.

Real Project Example

Imagine you're building an e-commerce admin dashboard.

The page contains:

Admin Dashboard

├── Header
├── Search
├── Revenue Chart
├── Sales Statistics
├── Orders Table
├── Customer List
└── Notifications

The orders table contains 5,000 records.

When an administrator types into the search field, the entire page becomes noticeably slower.

Initial implementation
function Dashboard() {
const [search, setSearch] = useState("");

return (
<>

  <RevenueChart />

  <OrdersTable search={search} />

  <CustomerList />
</>

);
}

The profiler reveals that several expensive components render during every search update.

Investigation

The profile shows:

Dashboard 150 ms
OrdersTable 110 ms
CustomerList 25 ms
RevenueChart 15 ms
Search 2 ms

The search field isn't the problem.

OrdersTable is.

Optimization

The table can be improved by:

Memoizing expensive derived data when appropriate.
Splitting the table into smaller components.
Memoizing stable child components when profiling shows it helps.
Virtualizing the large list.
Moving unrelated state closer to the components that use it.

After optimization:

Dashboard 55 ms
OrdersTable 32 ms
CustomerList 10 ms
RevenueChart 8 ms
Search 2 ms

More importantly, the search interaction feels substantially more responsive.

This is the important lesson:

The profiler helped identify where to investigate instead of relying on assumptions.

A Practical Profiling Workflow

When you encounter a slow React interaction, use this checklist:

  1. Reproduce the problem ↓
  2. Record the interaction ↓
  3. Find expensive components ↓
  4. Determine why they render ↓
  5. Inspect the component code ↓
  6. Apply one targeted optimization ↓
  7. Record the same interaction again ↓
  8. Compare the results ↓
  9. Verify real user experience

This approach is much safer than randomly adding memoization throughout an application.

Conclusion

Performance optimization starts with measurement.

When a React application feels slow, don't immediately reach for React.memo, useMemo, or useCallback.

First find out what's actually happening.

The React Profiler gives you a practical way to investigate rendering behavior and identify components worth examining.

The most important workflow is:

Profile → Identify → Understand → Optimize → Measure again.

Remember that a slow component isn't always caused by React itself. Expensive calculations, large lists, browser layout, network activity, and third-party JavaScript can all contribute to a slow interaction.

The best React performance optimization is therefore not about using the most optimization techniques.

It's about using the right technique for the measured problem.

Discussion

How do you usually find slow components in your React applications?

Do you rely on React DevTools Profiler, the browser Performance panel, or a combination of both?

Share your profiling workflow in the comments.

About the Author

Written by Muneeb Ansari

Founder of BiteGlitz

I enjoy building modern web applications, AI automation, and sharing practical knowledge with the developer community.

Website: https://biteglitz.site``

Top comments (0)