Last month, I opened our React dashboard and watched it take 6 full seconds to load.
Six seconds. In 2026. Unacceptable.
Users were complaining. Bounce rate was climbing. And every time I clicked a button, the UI would freeze for half a second before responding.
I spent one day diagnosing and fixing it. The app now loads in under 1.5 seconds.
Here's exactly what I found — and how I fixed it. 🚀
Step 0: Never Optimize Without Measuring First
This is the mistake most developers make. They guess what's slow and start randomly adding useMemo and React.memo everywhere.
Don't do that.
Before touching a single line of code, open React DevTools Profiler:
- Install React DevTools in Chrome
- Open DevTools → Profiler tab
- Click Record
- Interact with your slow component
- Stop recording → Look at the Flame Chart
💡 What to look for: Any component taking more than 50ms is a red flag. In 2026, Google measures Interaction to Next Paint (INP) — anything blocking the main thread hurts your SEO and user experience.
In my case, the profiler revealed 3 major problems. Here's each one and how I fixed it.
Problem 1: Unnecessary Re-Renders Everywhere
This was the biggest culprit. Our parent component was re-rendering on every state change — and dragging every single child component with it.
The broken code:
// ❌ Every time `count` changes, ALL children re-render
function Dashboard() {
const [count, setCount] = useState(0);
return (
<>
<button onClick={() => setCount(count + 1)}>Update</button>
<HeavyChart /> {/* Re-renders even though it doesn't use count */}
<UserTable /> {/* Same problem */}
<ActivityFeed /> {/* Same problem */}
</>
);
}
Every click on that button was re-rendering HeavyChart, UserTable, and ActivityFeed — even though none of them used count.
The fix — React.memo:
// ✅ Now these components only re-render when their own props change
const HeavyChart = React.memo(function HeavyChart() {
return <div>...chart...</div>;
});
const UserTable = React.memo(function UserTable({ users }) {
return <table>...table...</table>;
});
Result: Re-renders dropped by 70% for these components.
💡 2026 Update: If you're using the React Compiler (formerly React Forget), it handles memoization automatically. But if you haven't set it up yet,
React.memois still your best friend.
Problem 2: A 95KB JavaScript Bundle Loaded Upfront
Our app was shipping one massive JavaScript file containing every page, every component, and every library — even for pages the user might never visit.
I ran Webpack Bundle Analyzer to see what was inside:
npm install --save-dev webpack-bundle-analyzer
npx webpack-bundle-analyzer build/static/js/*.js
What I found was shocking. A charting library we used on ONE page was taking up 38KB of our bundle — loading for every single user on every single page.
The fix — Lazy Loading with React.lazy:
// ❌ Before — everything loaded upfront
import HeavyChartPage from './pages/HeavyChartPage';
import AdminPanel from './pages/AdminPanel';
import ReportsPage from './pages/ReportsPage';
// ✅ After — only loaded when user visits that page
import { lazy, Suspense } from 'react';
const HeavyChartPage = lazy(() => import('./pages/HeavyChartPage'));
const AdminPanel = lazy(() => import('./pages/AdminPanel'));
const ReportsPage = lazy(() => import('./pages/ReportsPage'));
function App() {
return (
<Suspense fallback={<div>Loading...</div>}>
<Routes>
<Route path="/charts" element={<HeavyChartPage />} />
<Route path="/admin" element={<AdminPanel />} />
<Route path="/reports" element={<ReportsPage />} />
</Routes>
</Suspense>
);
}
Result: Initial bundle size dropped from 95KB to 31KB. Load time went from 6 seconds to 2.8 seconds — just from this one change.
Problem 3: Expensive Calculations Running on Every Render
Our dashboard had a filtering + sorting feature for a table with 2,000+ rows. The filter function was running on every single render — even when the data hadn't changed.
// ❌ This runs on every render — even unrelated ones
function UserTable({ users, searchQuery }) {
// This heavy calculation runs EVERY time
const filteredUsers = users
.filter(user => user.name.includes(searchQuery))
.sort((a, b) => a.name.localeCompare(b.name));
return <table>...</table>;
}
The fix — useMemo:
// ✅ Only recalculates when users or searchQuery actually changes
function UserTable({ users, searchQuery }) {
const filteredUsers = useMemo(() => {
return users
.filter(user => user.name.includes(searchQuery))
.sort((a, b) => a.name.localeCompare(b.name));
}, [users, searchQuery]);
return <table>...</table>;
}
Result: The table interaction went from 340ms to 12ms. Instantly noticeable.
Bonus Fix: List Virtualization for Long Lists
Even after memoizing, rendering 2,000+ table rows in the DOM was still slow. The browser was creating 2,000 DOM nodes even though the user could only see 20 at a time.
The fix — react-window:
npm install react-window
import { FixedSizeList } from 'react-window';
// ❌ Before — renders ALL 2000 rows in the DOM
function UserList({ users }) {
return (
<div>
{users.map(user => <UserRow key={user.id} user={user} />)}
</div>
);
}
// ✅ After — only renders ~20 visible rows at any time
function UserList({ users }) {
const Row = ({ index, style }) => (
<div style={style}>
<UserRow user={users[index]} />
</div>
);
return (
<FixedSizeList
height={600}
itemCount={users.length}
itemSize={50}
width="100%"
>
{Row}
</FixedSizeList>
);
}
Result: Scrolling through 2,000 rows became buttery smooth.
The Final Results
Here's what one day of focused performance work achieved:
| Metric | Before | After |
|---|---|---|
| Initial Load Time | 6.0s | 1.4s |
| Bundle Size | 95KB | 31KB |
| Table Interaction | 340ms | 12ms |
| Re-renders per click | ~47 | ~8 |
Your React Performance Checklist
Before optimizing, always profile first. Then work through this list:
1. ✅ Run React DevTools Profiler — find what's actually slow
2. ✅ Add React.memo to components that re-render unnecessarily
3. ✅ Run Webpack Bundle Analyzer — find what's bloating your bundle
4. ✅ Lazy load routes and heavy components with React.lazy
5. ✅ Wrap expensive calculations in useMemo
6. ✅ Virtualize long lists with react-window
7. ✅ Enable React Compiler if on React 19+ — auto memoization!
The Real Lesson
Performance issues don't announce themselves. They sneak in slowly — one re-render here, one large import there — until suddenly your app feels like it's running through mud.
The fix isn't always complicated. In my case, four targeted changes — memoization, code splitting, useMemo, and list virtualization — cut load time by 77%.
The key is to measure first, fix second. Never optimize blindly.
Have you had a React performance nightmare in your own project? What was the culprit? Drop it in the comments — I'd love to compare war stories! 👇
Heads up: AI helped me write this.But the ideas, code review, and learning are all mine — AI just helped me communicate them better. I believe in being transparent about my process! 😊
Top comments (4)
hey! i'm a beginner web developer ofcourse still learning and exploring things, the unnecessary re-render issue it happens with me everytime i tried to built something the problem is i can't understand that i don't need to re-render these things always but the states trigger them , i used to create separate props and states to solve this but now i know that there's other simpler way thanks this post really gave me something valuable.
Thanks so much for sharing your experience!
You're absolutely right that "why is everything re-rendering?" moment happens to every React developer. It's one of those things they don't teach in tutorials, but you only really understand once you've struggled with it yourself.
The fact that you were already using separate props and states shows you're thinking in the right direction. Now you've got more tools in your toolbox!
Keep building, keep breaking things, and keep learning. That's the only way to get better.
Would love to see what you build next!
Thanks so much for sharing your experience!
You're most welcome, Ruth! Glad you found it helpful.
Have you run into any of these performance issues in your own projects? Would love to hear about your experience always great to learn from fellow devs.