React.js Real-Life Problem , How I Optimized a 5,000+ Row Table for Smooth UX (step-by-step)
Large client-side tables are a classic real-world React pain point. Render thousands of rows and the page freezes, initial load is slow and scrolling becomes laggy. In this article I’ll show a practical, step-by-step approach to fix this using virtualized rendering (react-window), plus tips for real production concerns like selection, sorting, infinite loading and measuring the improvement.
Problem statement
You have a table (e.g. transactions, users, logs) with thousands of rows. Symptoms:
What we want: render only the rows visible on screen so the table feels instant and uses minimal memory.
Step 1 — Reproduce & measure the baseline
Before changing anything, record the baseline so you can measure improvement.
(You can also run Lighthouse to measure initial load / time-to-interactive.)
Step 2 — Pick the right tool: react-window
For most tables, react-window is lightweight, simple and fast.
Install:
npm install react-window
# or
yarn add react-window
If you need infinite loading later, add:
npm install react-window-infinite-loader
Step 3 — Convert the table body to a virtualized list (core example)
Below is a small, complete component that replaces a heavy <tbody> with a FixedSizeList. It includes a sticky header and a virtualized body.
// VirtualizedTable.jsx
import React from "react";
import { FixedSizeList as List } from "react-window";
const Row = React.memo(({ index, style, data }) => {
const item = data[index];
return (
<div
style={{
...style,
display: "flex",
padding: "10px 12px",
boxSizing: "border-box",
borderBottom: "1px solid #eee",
alignItems: "center",
}}
>
<div style={{ flex: "0 0 80px" }}>{item.id}</div>
<div style={{ flex: "1 1 auto" }}>{item.name}</div>
<div style={{ flex: "0 0 160px", textAlign: "right" }}>{item.amount}</div>
</div>
);
});
export default function VirtualizedTable({ data, height = 600, rowHeight = 56 }) {
return (
<div style={{ border: "1px solid #ddd", borderRadius: 6, overflow: "hidden" }}>
{/* Header */}
<div style={{ display: "flex", padding: "12px", background: "#f7f7f7", fontWeight: 600 }}>
<div style={{ flex: "0 0 80px" }}>ID</div>
<div style={{ flex: "1 1 auto" }}>Name</div>
<div style={{ flex: "0 0 160px", textAlign: "right" }}>Amount</div>
</div>
{/* Virtualized list */}
<List
height={height}
itemCount={data.length}
itemSize={rowHeight}
width="100%"
itemData={data}
>
{Row}
</List>
</div>
);
}
Usage example:
const data = Array.from({ length: 5000 }, (_, i) => ({
id: i + 1,
name: `User ${i + 1}`,
amount: (Math.random() * 1000).toFixed(2),
}));
<VirtualizedTable data={data} />
Why this helps: only rows visible inside the height are mounted; offscreen rows aren’t in DOM , drastically lowers paint/scripting work.
Step 4 — Production hardening & best practices
const itemData = useMemo(() => ({ items: data, selectedId, onRowClick }), [data, selectedId, onRowClick]);
Step 5 — Sorting, filtering, selection
Step 6 — Infinite loading (optional)
If your API pages results, combine react-window with react-window-infinite-loader:
import InfiniteLoader from "react-window-infinite-loader";
const isItemLoaded = index => index < data.length;
<InfiniteLoader
isItemLoaded={isItemLoaded}
loadMoreItems={loadMoreItems} // function that fetches the next page
itemCount={hasMore ? data.length + 1 : data.length}
>
{({ onItemsRendered, ref }) => (
<List
height={600}
itemCount={data.length}
itemSize={56}
width="100%"
onItemsRendered={onItemsRendered}
ref={ref}
itemData={data}
>
{Row}
</List>
)}
</InfiniteLoader>
This gives seamless “infinite scroll” experience while remaining virtualized.
Step 7 — Measure after changes
Repeat Step 1 profiling. Expected qualitative improvements:
Quantify with before/after numbers for scripting/paint time from DevTools to show impact in your post readers love data.
Step 8 Edge cases & alternatives
Quick checklist (before you publish)
TL;DR
Stop rendering thousands of DOM rows virtualize. react-window is a tiny, robust way to render only what’s visible, dramatically improving load and scroll performance. Combine virtualization with memoization, stable props and server-side pagination for best results.
🔗 Resources
👉 1: Book 1:1 Mentorship / Pair Programming Help
👉 2: Learn Advanced React with My Favorite Udemy Courses
👉 3: Subscribe to My Newsletter
Get React + Frontend tips weekly, short, simple, and practical:
📣 CTA
Have you faced bugs like these? Or worse?
Drop a comment or DM , let’s debug together and build smarter.
Full Stack Developer | Software Developer | Scrum Master | Business Intelligence (BI)
1dAmazing! Thank you.
Software Developer @ Etelligens Technologies
4dHelpful insight, AYUSH
Freelance React & React Native Developer | Mobile and Web Apps for VC-Backed Startups | Remote Delivery
4dCFBR, Great Share