A genuinely common support request I have helped with involves a list component that performs fine with a small amount of test data but becomes noticeably sluggish once populated with realistic, larger amounts of actual data, with the underlying cause varying meaningfully between different specific situations despite the symptom looking similar on the surface.
Cause One: Rendering Every Item Regardless of Visibility
For genuinely long lists — hundreds or thousands of items — rendering every single item into the DOM simultaneously, even though only a small visible portion fits within the actual viewport at any given time, creates substantial unnecessary rendering work and a correspondingly large DOM that becomes expensive to manage.
How to confirm this is the cause: Check your actual list length against what is rendering. If you have a thousand items and all thousand are present in the DOM simultaneously, regardless of scroll position, this is very likely contributing significantly to the slowness you are experiencing.
The fix: Virtualization, using a library like react-window or react-virtualized, renders only the items currently visible within the viewport (plus a small buffer), dramatically reducing the actual DOM size and corresponding render cost regardless of how large your underlying data set actually is.
import { FixedSizeList } from 'react-window';
function VirtualizedList({ items }) {
return (
<FixedSizeList height={400} itemCount={items.length} itemSize={50}>
{({ index, style }) => (
<div style={style}>{items[index].name}</div>
)}
</FixedSizeList>
);
}
I measured this directly on a list of several thousand items — without virtualization, initial render and scroll performance was noticeably sluggish; with virtualization applied, both improved measurably, confirmed through the Profiler showing a dramatically reduced number of actually-rendered DOM nodes at any given time.
Cause Two: Missing or Incorrect Key Props
Using array index as a key, or omitting keys entirely, can cause React to incorrectly reconcile list items during updates, particularly when items are added, removed, or reordered, leading to unnecessary re-renders or even incorrect rendering of item state.
How to confirm this is the cause: Check your list rendering code for key={index} or missing key props entirely. If your list items can be reordered, filtered, or have items inserted/removed (rather than only ever appending to the end), index-based keys are a likely contributing issue.
The fix: Use a genuinely stable, unique identifier from your actual data (a database ID, a unique generated identifier) as the key, rather than array index, ensuring React can correctly track which specific item corresponds to which rendered element across updates, even when the list order or composition changes.
// Problematic for lists that reorder or filter
{items.map((item, index) => <Item key={index} data={item} />)}
// Correct: stable identifier from actual data
{items.map((item) => <Item key={item.id} data={item} />)}
Cause Three: Expensive Per-Item Render Logic
If each individual list item performs meaningful calculation or rendering work — complex formatting, nested component trees, expensive conditional logic — this per-item cost multiplies across your entire list, and even a moderate per-item cost becomes significant at scale with enough items.
How to confirm this is the cause: Profile a single item’s render time in isolation. If an individual item’s render genuinely takes meaningful time, this cost is multiplying across your full list length, contributing to overall list rendering slowness independent of the list length itself.
The fix: Move expensive calculations to memoized values (using useMemo, as covered in our dedicated guide) computed once rather than recalculated on every render, and consider whether each list item’s rendered complexity could reasonably be simplified without losing necessary functionality.
Cause Four: The Entire List Re-Rendering When Only One Item Changed
If updating a single item’s data causes your entire list to re-render, rather than just that specific item, this multiplies unnecessary render work across every unchanged item whenever any single item updates.
How to confirm this is the cause: Profile an update to a single item and check whether other, unrelated items are also re-rendering in that same profiling session, which would indicate this issue is occurring.
The fix: Wrapping individual list item components in React.memo (covered in detail in our dedicated guide) allows React to skip re-rendering items whose specific props have not changed, even when the parent list component itself re-renders due to one specific item’s update.
Combining Virtualization With Memoization
These two techniques address genuinely distinct aspects of list performance and work well together rather than being mutually exclusive alternatives. Virtualization reduces how many items are rendered at all at any given time; memoization ensures that among the items that are rendered, unchanged ones skip unnecessary re-renders. For genuinely large, frequently-updating lists, applying both techniques together often produces better results than either alone.
A Diagnostic Sequence for Slow List Rendering
When facing slow list rendering, working through these checks in this general order helps identify the actual cause efficiently:
First, check whether your list length and rendering approach mean every item renders regardless of visibility, since this is often the most impactful issue for genuinely long lists.
Second, check your key prop usage, particularly if your list supports reordering, filtering, or insertion/removal beyond simple appending.
Third, profile individual item render cost to check whether per-item complexity is contributing meaningfully at your actual list scale.
Fourth, check whether single-item updates are causing unnecessary re-renders across your entire list, suggesting memoization would help.
A Quick Reference Summary
| Cause | Symptom | Fix |
|---|---|---|
| All items rendered regardless of visibility | Slowness scales with total list length | Virtualization (react-window/react-virtualized) |
| Index-based or missing keys | Incorrect rendering on reorder/filter | Stable unique identifier as key |
| Expensive per-item render logic | Slowness even with moderate list length | Memoize expensive per-item calculations |
| Entire list re-renders on single item change | Unrelated items re-render unnecessarily | React.memo on individual list items |
What Actually Resolved Most of the Support Cases
Across the various list performance issues I have helped diagnose, virtualization for genuinely long lists and proper key usage for lists with reordering or filtering were the two most consistently impactful fixes, addressed first before considering the more targeted memoization fixes, which matter more for lists with frequent partial updates rather than the more fundamental rendering volume and reconciliation issues these two more foundational fixes address.
How many items are in your list, and what specific behavior (initial load, scrolling, updates) feels slow? Describe your situation and I can help you identify which of these causes is most likely.
🔗 Recommended Reading