React Window
react-window is a highly performant and minimalist React component library for efficiently rendering large lists and grid data using windowing (also known as virtualization). It optimizes performance by rendering only the items currently visible within the viewport, significantly reducing the DOM nodes, memory footprint, and rendering time compared to rendering all items in a large dataset. The library provides several specialized components, including `FixedSizeList`, `VariableSizeList`, `FixedSizeGrid`, and `VariableSizeGrid`, to cater to different use cases like lists with fixed item sizes or dynamic item sizes. The current stable version is 2.2.7, and it maintains an active release cadence, frequently publishing patch versions to address bugs and enhance TypeScript compatibility, especially for newer React versions. Its key differentiators include a small bundle size, strong focus on performance, and a straightforward API, making it a popular choice for optimizing UI rendering in applications and development tools like React DevTools.
Common errors
-
Error: FixedSizeList: Each child passed to FixedSizeList or FixedSizeGrid must be a React component. e.g. <FixedSizeList>{MyRow}</FixedSizeList>cause This error occurs when you pass an already rendered JSX element or an inline function that returns JSX directly, instead of passing a reference to a functional React component.fixDefine your row or cell renderer as a separate functional React component (e.g., `const MyRow = ({ index, style }) => <div style={style}>...</div>;`) and then pass its reference to the virtualization component: `<FixedSizeList>{MyRow}</FixedSizeList>`. -
TypeError: Cannot read properties of undefined (reading 'scrollToItem') when calling ref methods.
cause This usually indicates that the `ref.current` value for `FixedSizeList` or `FixedSizeGrid` is `null` or `undefined` at the time the imperative method (like `scrollToItem`, `scrollTo`) is invoked. This often happens if the ref is not properly attached or accessed before the component has mounted.fixEnsure the ref is correctly initialized using `useRef` and that `ref.current` is accessed only after the component is mounted. Calling imperative methods should ideally be done within a `useEffect` hook, a user event handler, or after checking `ref.current` for nullability. -
Invariant Violation: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object.
cause While a generic React error, when seen with `react-window`, it frequently points to missing or invalid required props for the virtualization component. Specifically, `height`, `width`, `itemCount`, and `itemSize` (for fixed-size components) are critical and must be valid numbers.fixDouble-check that all mandatory props (`height`, `width`, `itemCount`, `itemSize` for fixed lists/grids, or corresponding size-getter functions for variable lists/grids) are provided and are of the correct type (usually numbers for fixed sizes).
Warnings
- breaking The TypeScript return type for `List` and `Grid` components, as well as the `rowComponent` and `cellComponent` props, was changed from `ReactNode` to `ReactElement`. This adjustment, primarily for React 18 compatibility, ensures stricter type checking and may require minor updates to explicit type annotations in consuming applications if they relied on the broader `ReactNode` type.
- breaking When an invalid index is passed to imperative scroll-to methods (e.g., `scrollToItem`), the library now throws a `RangeError` instead of a generic `Error`. While the error's behavior is similar, the specific error class has changed.
- gotcha The `useDynamicRowHeight` hook now explicitly avoids instantiating `ResizeObserver` during server-side rendering (SSR) to prevent potential issues like client-side hydration mismatches and unnecessary resource allocation on the server. Dynamic row heights are inherently a client-side concern.
Install
-
npm install react-window -
yarn add react-window -
pnpm add react-window
Imports
- FixedSizeList
const FixedSizeList = require('react-window').FixedSizeList; // Incorrect CommonJS pattern for modern React/TypeScript projectsimport { FixedSizeList } from 'react-window' - VariableSizeList
import VariableSizeList from 'react-window'; // 'react-window' does not provide a default export for components
import { VariableSizeList } from 'react-window' - FixedSizeGrid
import { Grid } from 'react-window'; // The fixed-size grid is specifically 'FixedSizeGrid'import { FixedSizeGrid } from 'react-window'
Quickstart
import React from 'react';
import { FixedSizeList } from 'react-window';
import { createRoot } from 'react-dom/client';
const Row = ({ index, style }) => {
// `style` prop is crucial for positioning items correctly
return (
<div style={{ ...style, background: index % 2 ? '#eee' : 'white', padding: '10px' }}>
Item {index + 1}
</div>
);
};
const MyVirtualList = () => (
<FixedSizeList
height={300} // Total height of the scrollable container
width={400} // Total width of the scrollable container
itemCount={1000} // Total number of items in the list
itemSize={50} // Height of each item
>
{Row}
</FixedSizeList>
);
const container = document.getElementById('root');
if (container) {
const root = createRoot(container);
root.render(<MyVirtualList />);
}