react-virtualized
repository·master·Indexed 12 days ago
https://github.com/bvaughn/react-virtualizedA collection of React components for efficiently rendering large, scrollable lists and complex tabular data through virtualization. Version 9.22.6 includes core components like List, Grid, Table, and Masonry, as well as High-Order Components such as AutoSizer for responsive dimensions, CellMeasurer for dynamic content sizing, and InfiniteLoader for lazy-loading datasets.
What's inside react-virtualized
- react-virtualized provides React components for efficiently rendering large lists and tabular data. It is designed to handle high-performance scrolling and virtualization to maintain smooth UI interactions even with massive datasets.
Explore react-virtualized components and HOCs
masterThe
react-virtualizedlibrary provides several core components and High-Order Components (HOCs) to handle large datasets efficiently.Core Components
- Collection: A generic base for virtualized collections.
- Grid: A two-dimensional virtualized grid.
- List: A one-dimensional virtualized list.
- Masonry: A masonry-style layout for items of varying sizes.
- Table: A virtualized table, which includes support for
ColumnandSortDirectioncomponents.
High-Order Components (HOCs)
- ArrowKeyStepper: Enables keyboard navigation.
- AutoSizer: Automatically sizes the component to fit its parent container.
- CellMeasurer: Measures the size of cells for dynamic content.
- ColumnSizer: Manages column sizing in grids or tables.
- InfiniteLoader: Handles loading data in chunks as the user scrolls.
- MultiGrid: Manages multiple synchronized grids.
- ScrollSync: Synchronizes scrolling between multiple components.
- WindowScroller: Synchronizes scrolling with the browser window.
How the Masonry component works
masterThe
Masonrycomponent uses windowing to efficiently display dynamically-sized, user-positioned cells. It operates in two distinct phases:- Measurement Phase: Uses estimated cell sizes from
cellMeasurerCacheto batch-measure items. It uses a naive layout algorithm to stack items until the viewport is filled. Measurements are permanently cached using akeyMapperto ensure performance. If actual sizes differ from estimates, a new measurement pass is triggered. - Layout Phase: Uses an external
cellPositionerfunction to determine the exact{ left, top }coordinates for each cell. TheMasonrycomponent caches these returned positions for fast access.
Key Constraints:
- Vertical Windowing: It only supports vertical scrolling; horizontal scrolling is not supported.
- Column Alignment: All items in a single column must have the same width and the same left position. Items cannot span multiple columns.
- Synchronous Measurement: Cell measurements must be synchronous. Using the asynchronous
measureparameter inCellMeasureris not supported because it would cause frequent layout invalidation. - Animations: Supports simple animations (like sliding into place on initial reveal) but does not support complex animations like flying from one position to another during a resize.
- Measurement Phase: Uses estimated cell sizes from
Implement the rowRenderer function
masterThe
rowRendereris a required function responsible for rendering a single row. It is called for each row that needs to be rendered.Crucial Requirements:
- Apply
style: You MUST pass the providedstyleobject to the root element of your rendered row. This object contains theposition,left,top,height, andwidthnecessary for theListto position the row correctly. - Provide
key: You MUST pass the providedkeyto the root element for React's reconciliation. - Avoid Vertical Overflow: It is highly recommended that rows use
overflow-y: hiddento prevent individual items from intercepting scroll events, which can break the list's scrolling behavior.
Arguments provided to
rowRenderer:index: The index of the row.isScrolling: Boolean indicating if the list is currently being scrolled.isVisible: Boolean indicating if the row is visible (not just overscanned).key: A unique key for the row.parent: A reference to theListinstance.style: The style object required for positioning.
function rowRenderer({ index, // Index of row isScrolling, // The List is currently being scrolled isVisible, // This row is visible within the List key, // Unique key within array of rendered rows parent, // Reference to the parent List (instance) style, // Style object to be applied to row (to position it); }) { const content = isScrolling ? '...' : <User user={list[index]} />; return ( <div key={key} style={style}> {content} </div> ); }- Apply
Compare react-virtualized with react-window
masterBefore addingreact-virtualizedto your project, consider usingreact-windowas a lighter-weight alternative. You can find a detailed comparison of how the two libraries differ in thereact-windowrepository.Use AutoSizer to automatically adjust dimensions
masterThe
AutoSizercomponent is a high-order component that automatically calculates and provides the width and height of its parent container to a single child. This is useful for components likeListthat require explicit dimensions but need to fill available space dynamically.Usage Pattern
AutoSizeruses a render prop pattern. You must provide a function as itschildrenprop. This function receives an object containing the currentheightandwidthand should return a React element.Important: Flexbox Warning
Avoid placing
AutoSizeras a direct child of a flexbox container. Because flex containers allow children to grow andAutoSizergreedily expands to fill space, this can trigger an infinite resize loop. To prevent this, wrapAutoSizerin a standard block element (like a<div>) inside the flex container.<AutoSizer> {({ height, width }) => ( <List height={height} width={width} // ... other props /> )} </AutoSizer>Use InfiniteLoader for just-in-time data fetching
masterThe
InfiniteLoadercomponent manages the fetching of data as a user scrolls through a list or grid. It is designed to work best withListandTablecomponents, but can also be used withGrid. Note that it is not compatible with theCollectioncomponent.To use it, you must provide a child function that renders your virtualized component and connects it to the loader using the provided
onRowsRenderedandregisterChildparameters.<InfiniteLoader isRowLoaded={isRowLoaded} loadMoreRows={loadMoreRows} rowCount={remoteRowCount} > {({ onRowsRendered, registerChild }) => ( <List onRowsRendered={onRowsRendered} ref={registerChild} {...otherProps} /> )} </InfiniteLoader>Use WindowScroller to sync List or Table with window scroll
masterThe
WindowScrollercomponent enables aTableorListcomponent to be scrolled based on the window's scroll positions. This is ideal for creating layouts like Facebook or Twitter news feeds where the list is part of the main page scroll rather than inside a fixed-height container.Limitations:
- It does not currently work with horizontally-scrolling
Gridcomponents, as horizontal scrolls reset the internalscrollTop. Use it withTableorListonly.
import React from 'react'; import { List, WindowScroller } from 'react-virtualized'; import 'react-virtualized/styles.css'; // Basic usage pattern <WindowScroller> {({ height, isScrolling, onChildScroll, scrollTop }) => ( <List autoHeight height={height} isScrolling={isScrolling} onScroll={onChildScroll} scrollTop={scrollTop} {...otherProps} /> )} </WindowScroller>- It does not currently work with horizontally-scrolling
Track loaded rows manually in InfiniteLoader
masterBecause
InfiniteLoaderis not a stateful component, it does not track which rows have been requested. You must manage this state in your own component to prevent duplicate loading requests. A common pattern is to use a map to track the status (e.g.,LOADINGorLOADED) of each row index._isRowLoaded ({ index }) { const { loadedRowsMap } = this.state // No entry in this map signifies that the row has never been loaded before // An entry (either LOADING or LOADED) can be treated as loaded as far as InfiniteLoader is concerned return !!loadedRowsMap[index] }How to trigger re-renders for shallowCompare changes
masterBy default, all
react-virtualizedcomponents useshallowCompareto avoid unnecessary re-renders. If your data changes (e.g., a list is re-sorted) but the props passed to the component remain the same (e.g., the array reference or length hasn't changed), the component may not update.Method 1: Pass-thru props
Pass an additional property that changes when your data changes.
shallowComparewill detect changes to any prop, even those not declared inpropTypes.Example for a sorted list:
<List {...listProps} sortBy={sortBy} />Method 2: Public methods
You can force a re-render using specific component methods:
GridandCollection: Use the standard ReactforceUpdate()method.TableandList: CallforceUpdateGrid()to ensure the innerGridis also updated.MultiGrid: CallforceUpdateGrids()to ensure all innerGrids are updated.
How AutoSizer works
masterThe
AutoSizercomponent decorates a React element and automatically manageswidthandheightproperties so that the decorated element fills the available space. This is useful for components likeGrid,Table, andListthat require explicit dimensions.Important Implementation Details:
- It uses the
javascript-detect-element-resizealgorithm. - It performs direct DOM manipulation on its parent outside of React's VirtualDOM.
- If the parent has
position: static(the default),AutoSizerwill change it toposition: relative. - It injects a sibling
divto measure size.
<AutoSizer> {({ width, height }) => ( <Component width={width} height={height} /> )} </AutoSizer>- It uses the
How ScrollSync synchronizes scrolling between components
masterScrollSyncis a Higher Order Component (HOC) designed to synchronize the scroll position between two or more virtualized components (such asGridorList).It works by providing a render function as its child. This function receives the current scroll state and an
onScrollcallback. To enable synchronization, you must pass theonScrollcallback to at least one of the child components. When that component scrolls, theonScrollfunction updates the shared scroll offsets (scrollTop,scrollLeft, etc.), which are then passed down to the other components to keep them in sync.<ScrollSync> {({ onScroll, scrollTop, scrollLeft }) => ( <> {/* Pass onScroll to one component to drive the sync */} <Grid onScroll={onScroll} scrollTop={scrollTop} scrollLeft={scrollLeft} {...otherProps} /> {/* Pass the scroll offsets to the other component to keep it in sync */} <List scrollTop={scrollTop} scrollLeft={scrollLeft} {...otherProps} /> </> )} </ScrollSync>