React Window: Build Fast Virtualized Lists for Large Datasets

A compact, practical guide to react-window — installation, FixedSizeList and VariableSizeList examples, infinite scroll, and performance troubleshooting.

Why use react-window (and when not to)

When your UI must render hundreds or thousands of list items, naive rendering kills performance: long initial paints, janky scrolling, and high memory usage. react-window solves this by rendering only the visible subset of items and a small buffer. That yields smoother scroll performance and lower memory consumption without radically changing how you write components.

It’s intentionally minimal—focused on the core virtualization primitives. If you want a tiny bundle and predictable, fast list rendering, react-window is often the right choice. If you need dozens of out-of-the-box widgets (grid, cell measurers, complex caching policies), consider alternatives like react-virtualized or react-virtuoso.

Use react-window for lists and grids with stable or measurable item sizes, large datasets, and when you care about keeping bundle size low. Avoid it for complex dynamic layouts where every item’s height is unknown and expensive to measure unless you’re prepared to implement measurement strategies.

Installation & setup

Get started by installing the package. With npm:

npm install react-window

Or with yarn:

yarn add react-window

Then import the primitives you need. The most common entry points are FixedSizeList and VariableSizeList :

import { FixedSizeList, VariableSizeList } from 'react-window';

If you want a practical walkthrough, see this react-window tutorial and the official repository react-window.

Core concepts: viewport, overscan, and item size

react-window centers on three ideas: the viewport (the visible area), item size (fixed or variable), and overscan (rendering a few extra items to avoid pop-in during scroll). Understanding these is key to predictable performance.

Fixed-size lists assume identical item heights (or widths for horizontal lists) which simplifies layout math and reduces runtime overhead. Variable-size lists require bookkeeping of each item’s size and occasional recalculations for jumpy changes.

Overscan prevents white gaps during fast scrolling by rendering items just beyond the viewport. Tune overscan to balance memory and perceived smoothness—higher overscan reduces flicker at the cost of extra DOM nodes.

FixedSizeList: minimal example

Use FixedSizeList when every item shares the same height. The API is tiny: you provide height, itemCount, itemSize, and a render function for each row. This makes it the fastest and simplest case.

import { FixedSizeList as List } from 'react-window';
function Row({ index, style }) {
return 
Row {index}
; } {Row}

Note: pass the style prop to each row element to ensure proper positioning. Forgetting that causes layout problems and broken virtualization. If your rows contain interactive elements, they behave normally—only the offscreen DOM nodes are omitted.

When rendering complex rows, move heavy computations out of the render path (memoize or precompute). Also consider using React’s memo for row components to avoid unnecessary re-renders as the list scrolls.

VariableSizeList: when items vary

VariableSizeList supports items with differing heights. You must provide an itemSize function or an array of sizes so react-window can compute offsets and visible ranges.

import { VariableSizeList as VList } from 'react-window';
const sizes = new Array(10000).fill(0).map((_,i) => (i % 5 === 0 ? 80 : 40));
 sizes[index]}
width={'100%'}
>
{({ index, style }) => 
Item {index}
}

For truly dynamic heights (content that changes after render), measure items after mount (ResizeObserver or refs), keep a size map, and call listRef.resetAfterIndex(index, true) to force recalculation. This pattern requires a bit more plumbing but is robust.

Keep an eye on reflows: measuring too often negates the benefits of virtualization. Batch measurements and debounce resets to maintain a smooth UI.

Infinite scroll with react-window

react-window renders only what’s visible, so infinite loading needs a trigger when the user nears the end. Two common approaches: use a sentinel element with IntersectionObserver, or integrate react-window-infinite-loader .

Conceptually, watch the index of the last rendered item or a bottom sentinel. When it crosses a threshold (e.g., within 10 items), fetch the next page and append to your data array. Update itemCount and the list will render the new items.

Example pattern: maintain an isLoading flag, call fetchMore when needed, and prevent duplicate calls. If you use VariableSizeList, ensure the size map is extended for new items or use sensible defaults until measurements are available.

Performance tips and best practices

Small changes often make the biggest difference. Avoid inline functions and objects for row props (they break referential equality and cause re-renders). Use memoized row components and stable keys. Keep heavy computations out of render paths.

Tune overscan carefully: for mobile devices, a small overscan (1–3 items) is often enough; for desktop, you can afford more. Default caching and buffering are conservative—profile with React DevTools Performance tab or your preferred profiler.

When dealing with images or media inside rows, lazy-load or use placeholders. Large images in offscreen rows still consume memory if preloaded—only load resources when items are near the viewport.

  • Use FixedSizeList when possible for simpler, faster rendering.
  • Memoize row components and avoid unnecessary props changes.
  • Measure and batch updates for VariableSizeList; call resetAfterIndex sparingly.

Common pitfalls & debugging

Broken layout: the most frequent issue is not applying the provided style prop to row elements. The style contains position, transform, and size values required for virtualization. Always forward style to the top-level row element.

Incorrect scroll offsets: make sure width/height and itemSize are correct. Off-by-one errors in itemCount or misreported item sizes produce visual gaps or jumps. If using dynamic sizes, ensure your size cache updates after content changes.

Large re-renders: if the whole list re-renders frequently, check parent component identity changes, context updates, or props passed into the list that are recreated on every render. Use React.memo, useCallback, and stable refs to reduce churn.

Small checklist before shipping

Before you ship a virtualized list, run through this quick checklist: verify that the style prop is forwarded, test on low-end devices, validate memory usage under a long scroll session, and ensure images and media load lazily.

Also test accessibility: keyboard navigation, focus management, and screen reader behavior. Virtualized lists may hide offscreen content from assistive tech; ensure your app exposes necessary context or virtual focus management if required.

If SEO is a concern for item content, remember that virtualized content is not rendered to the DOM until visible. For crawlers or server-side rendering, provide alternative paginated or pre-rendered content where necessary.

Resources & backlinks

Official repo and docs: react-window. A concise walkthrough: react-window tutorial. For infinite loading helpers, see react-window-infinite-loader.

These references are helpful when you need deeper examples, patterns for measurement, or integration snippets for frameworks like Next.js.


FAQ

How does react-window differ from react-virtualized?

Short answer: react-window is smaller and focuses on core virtualization primitives; react-virtualized is larger with many widgets.

Why it matters: pick react-window for minimal bundle impact and predictable lists. Choose react-virtualized if you need built-in advanced widgets and don’t mind the size trade-off.

How do I implement infinite scroll with react-window?

Short answer: detect when the user nears the end (IntersectionObserver or index threshold) and append data; update itemCount.

Implementation tips: throttle/lock fetches, show a loading placeholder row, and use a small overscan to avoid visible gaps during loading. Consider react-window-infinite-loader for a helper wrapper.

How do I render variable-height items in react-window?

Short answer: use VariableSizeList and provide item sizes or measure items and call listRef.resetAfterIndex when sizes change.

Measurement pattern: measure after mount with ResizeObserver or refs, update a size map, and reset the list from the first changed index. Debounce resets to avoid layout thrashing.

Semantic Core

Primary keywords:
- react-window
- React window virtualization
- react-window tutorial
- react-window installation
- React performance optimization
Secondary keywords:
- React virtualized list
- react-window example
- React large list rendering
- react-window setup
- React scroll performance
- react-window FixedSizeList
- react-window VariableSizeList
- React list component
- React infinite scroll
- react-window getting started
Clarifying / LSI phrases:
- virtualized list react
- FixedSizeList example
- VariableSizeList usage
- infinite loader react-window
- virtual scrolling performance
- list virtualization tutorial
- react-window vs react-virtualized
- measuring item height react-window
- overscanCount react-window
- listRef.resetAfterIndex


Share

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *