React-window: Efficient Virtualized Lists — Tutorial & Examples


React-window: Efficient Virtualized Lists — Tutorial & Examples

Short summary: This practical guide shows how to install and set up react-window, when to use FixedSizeList vs VariableSizeList, how to implement virtualized infinite scroll, and performance best practices to render very large lists in React with minimal memory and smooth scrolling.

Why react-window and when to use it

If your React app renders long lists — thousands of rows, lots of images, or complex item components — normal rendering kills performance: high initial paint times, janky scroll, and heavy memory use. react-window solves that by rendering only visible rows (virtualization), dramatically reducing DOM nodes and paint cost.

Use react-window when you need predictable, smooth scroll performance and low memory overhead for lists, grids, or item collections. It’s intentionally minimal: small bundle size, fast, and focused on virtualization rather than providing a full feature-rich list framework.

Don’t reach for react-window when your list is small (dozens of items), when you rely on complex DOM interactions for offscreen items, or when you’re already using a grid solution that meets your needs. For very feature-heavy needs like cell measurement caching, consider complementing react-window with small helpers or other libraries.

Getting started: install and basic setup

Installing react-window is straightforward. It has no runtime dependencies and integrates easily into React projects. Run one of these commands from your project root to install:

npm install react-window
# or
yarn add react-window

After installing, import the list components you need — the two core ones are FixedSizeList and VariableSizeList. FixedSizeList is simpler and faster when every item has the same height; VariableSizeList handles variable heights at the cost of slightly more bookkeeping.

For a guided walkthrough and practical examples, see this practical guide: Getting Started with react-window (tutorial). It covers setup, examples, and real-world tips to get you production-ready quickly.

Core examples: FixedSizeList and VariableSizeList

Here are minimal, copy-pasteable examples showing the typical setup for both list types. These snippets focus on the key props so you can drop them into your app and adapt.

FixedSizeList (same-height rows)

FixedSizeList is the go-to when every item has a consistent height or width. It is the most performant: calculation is straightforward so scroll math is cheap.

import { FixedSizeList as List } from 'react-window';

function Row({ index, style, data }) {
  return (
    <div style={style}>
      {data[index]}
    </div>
  );
}

// in render:
<List
  height={600}            // viewport height
  itemCount={items.length}
  itemSize={50}           // row height in px
  width="100%"
  itemData={items}
/>

Note: style prop passed to Row is required — it positions the item correctly. Provide itemSize in pixels (or a number) and ensure height/width reflect your container.

VariableSizeList (dynamic heights)

When item heights vary, VariableSizeList lets you provide a size for each index and preserves scroll position when heights change. You must measure or know item sizes ahead or measure them on the fly and call resetAfterIndex.

import { VariableSizeList as List } from 'react-window';

const sizes = new Array(items.length).fill(50).map((_, i) => 30 + (i % 5) * 10);

function Row({ index, style, data }) {
  return <div style={style}>{data[index]}</div>;
}

// in render:
<List
  height={600}
  itemCount={items.length}
  itemSize={index => sizes[index]}
  width="100%"
  itemData={items}
/>

When heights change (e.g., after images load), call listRef.resetAfterIndex(changedIndex) to recompute layout from that index onward. That keeps scroll continuity smooth.

Infinite scroll, large lists, and scroll performance

react-window handles DOM virtualization; combining it with windowing-style data loading gives infinite scroll. For very large datasets, keep remote paging separate from virtualization: only fetch the data you need based on visible range, preload a buffer, and append to your dataset.

Pattern: maintain an array of loaded items and a sentinel buffer. When the viewport approaches unloaded indexes (via onItemsRendered callback), trigger a paged fetch and append data. Avoid adding huge numbers of placeholder nodes — instead track unloaded slots and render lightweight skeletons for them.

For optimal scroll performance:

  • Prefer FixedSizeList when possible — fewer calculations means smoother scrolling.
  • Avoid heavy per-item rendering (large images, expensive layout). Use memoization and virtualization to reduce re-renders.
  • Use requestAnimationFrame, debouncing, and passive event listeners where needed for scroll-linked work outside of rendering.

Advanced tips and pitfalls

Keep these production-focused tips in your pocket:

1) Memoize item renderers. If an item is expensive, wrap it in React.memo and supply stable props (avoid inline functions unless memoized). This dramatically reduces React reconciliation work as virtualization changes which items mount.

2) Image and media handling. Lazy-load images inside items and reserve height (CSS aspect-ratio or fixed height) to prevent layout shifts that confuse variable-size lists. For VariableSizeList, measure and then call resetAfterIndex when sizes settle.

3) Accessibility. Virtualization may remove off-screen items from the DOM, which can affect screen readers. Consider aria-live regions or offscreen pre-rendering for critical announcements, and ensure keyboard focus management is handled when items mount/unmount.

Performance checklist before shipping

Run this brief checklist to catch common regressions:

  • Verify smooth scroll with a large local dataset (simulate thousands of rows).
  • Profile React renders; ensure items only re-render when their data changes.
  • Measure paint times and first contentful paint; virtualization should reduce large initial paints.

Small wins, like using FixedSizeList and memoized rows, often yield the biggest UX improvements.

Expanded Semantic Core (grouped)

Primary keywords

  • react-window
  • React window virtualization
  • react-window tutorial
  • react-window installation
  • react-window example

Secondary keywords

  • React virtualized list
  • React large list rendering
  • react-window setup
  • react-window FixedSizeList
  • react-window VariableSizeList
  • React list component

Clarifying / intent-based & LSI phrases

  • React scroll performance
  • React performance optimization
  • React infinite scroll
  • React virtualized infinite scroll
  • render large lists in React
  • virtualized list example
  • how to use react-window

Backlinks and resources

For a thorough, hands-on walkthrough and more examples, follow this tutorial: react-window tutorial. It presents real demo code and pragmatic trade-offs for production.

If you want to jump straight to a getting-started guide, check this: Getting Started with react-window.

FAQ

How do I install and set up react-window?

Install via npm or yarn (npm install react-window), import the component you need (FixedSizeList or VariableSizeList), and render it with required props: height, width, itemCount, and itemSize or itemSize function. Provide a row renderer that applies the supplied style prop to each item.

When should I use FixedSizeList vs VariableSizeList?

Use FixedSizeList when every row has the same height — it’s faster and simpler. Use VariableSizeList when row heights differ; you’ll provide a size function or measurements and may need to call resetAfterIndex when sizes change.

How can I implement infinite scroll with react-window?

Combine react-window’s onItemsRendered callback with paged fetching: when the rendered range approaches the end of your loaded array, trigger an API fetch for the next page, append results, and render placeholders while loading. Keep a buffer to avoid visible loading gaps.