You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React-virtualized:calcRowHeight返回0时忽略行渲染的问题求助

React-Virtualized MultiGrid: Avoid Rendering Rows with Height 0 for Large Datasets

Problem Description

I'm using react-virtualized's MultiGrid component to render a large dataset. My current approach uses a toggle state to show/hide rows by returning 0 or 25 in calcRowHeight, and triggers recomputeGridSize when the toggle changes. This works fine for small datasets, but with large ones (e.g. hiding the first 2000 rows), react-virtualized still renders those 0-height rows, causing browser memory overload. I can't modify the original dataset, so how do I make react-virtualized skip rendering rows when calcRowHeight would return 0?

Here's my current code:

class ImportContainer extends React.Component<IImportContainerProps, IImportContainerState> {
  grid;
  componentDidUpdate(prevProps) {
    if (prevProps.toggleState !== this.props.toggleState) {
      this.refreshGridRows(0, 0);
    }
  }
  componentWillUnmount() {}
  refreshGridRows = (start: number = 0, end: number = (this.state.gridRowCount - this.state.fixedRowCount)) => {
    this.grid.recomputeGridSize({columnIndex: this.state.fixedColumnCount, rowIndex: 0});
  }
  calcRowHeight = (I) => {
    if (this.state.myData[I.index].randomBool === this.props.toggleState) {
      return 0;
    } else {
      return 25;
    }
  }
  render() {
    return <> 
      <AutoSizer>
        {({ height, width }) => <MultiGrid ref={this._setRef} rowHeight={this.calcRowHeight} [...] />}
      </AutoSizer>
    </>;
  }
}
export default ImportContainer;

Solution: Map Visible Rows Instead of Using 0 Height

I've run into this exact issue before—returning 0 from calcRowHeight doesn't prevent react-virtualized from creating DOM elements for those rows; it just makes them invisible. For large datasets, this adds up to massive memory bloat. Instead, we need to only pass the rows that should be rendered to MultiGrid, while maintaining a mapping to the original dataset indices.

Here's how to implement this:

1. Track Visible Row Indices

Add a state variable to store the indices of rows that should be visible in the original dataset:

state = {
  // ... your existing state
  visibleRowIndices: []
};

2. Compute Visible Rows on Toggle Change

Update your logic to recalculate visibleRowIndices whenever toggleState changes, instead of just calling recomputeGridSize:

componentDidMount() {
  // Initialize visible rows when the component mounts
  this.updateVisibleRows();
}

componentDidUpdate(prevProps) {
  if (prevProps.toggleState !== this.props.toggleState) {
    this.updateVisibleRows();
  }
}

updateVisibleRows = () => {
  const { myData } = this.state;
  const { toggleState } = this.props;
  // Filter original indices to only include rows that should be shown
  const visibleIndices = myData
    .map((_, index) => index)
    .filter(index => myData[index].randomBool !== toggleState);
  
  this.setState({ visibleRowIndices: visibleIndices }, () => {
    // After state updates, tell MultiGrid to recompute layout sizes
    if (this.grid) {
      this.grid.recomputeGridSize({ columnIndex: this.state.fixedColumnCount, rowIndex: 0 });
    }
  });
};

3. Adjust MultiGrid Props

Modify the MultiGrid props to use the visible row count, and map the rendered row index back to the original dataset index:

  • Set rowCount to visibleRowIndices.length (so MultiGrid only renders actual visible rows)
  • Update cell renderers to use visibleRowIndices[rowIndex] to fetch the original data
  • Replace calcRowHeight with a fixed value (since we're no longer hiding rows via height)

4. Updated Full Code

class ImportContainer extends React.Component<IImportContainerProps, IImportContainerState> {
  grid;

  state = {
    // ... your existing state (myData, fixedRowCount, fixedColumnCount, gridRowCount)
    visibleRowIndices: []
  };

  componentDidMount() {
    this.updateVisibleRows();
  }

  componentDidUpdate(prevProps) {
    if (prevProps.toggleState !== this.props.toggleState) {
      this.updateVisibleRows();
    }
  }

  componentWillUnmount() {}

  updateVisibleRows = () => {
    const { myData } = this.state;
    const { toggleState } = this.props;
    const visibleIndices = myData
      .map((_, index) => index)
      .filter(index => myData[index].randomBool !== toggleState);
    
    this.setState({ visibleRowIndices: visibleIndices }, () => {
      if (this.grid) {
        this.grid.recomputeGridSize({ columnIndex: this.state.fixedColumnCount, rowIndex: 0 });
      }
    });
  };

  // Fixed row height since we only render visible rows now
  calcRowHeight = () => 25;

  _setRef = (ref) => {
    this.grid = ref;
  };

  render() {
    const { visibleRowIndices, fixedRowCount, fixedColumnCount } = this.state;

    return (
      <AutoSizer>
        {({ height, width }) => (
          <MultiGrid
            ref={this._setRef}
            rowHeight={this.calcRowHeight}
            rowCount={visibleRowIndices.length}
            fixedRowCount={fixedRowCount}
            fixedColumnCount={fixedColumnCount}
            // Map rendered row index back to original dataset index
            cellRenderer={({ columnIndex, rowIndex, key, style }) => {
              const originalRowIndex = visibleRowIndices[rowIndex];
              const rowData = this.state.myData[originalRowIndex];
              return (
                <div key={key} style={style}>
                  {/* Render your cell content using rowData */}
                </div>
              );
            }}
            {.../* Your other MultiGrid props */}
          />
        )}
      </AutoSizer>
    );
  }
}

export default ImportContainer;

Key Notes

  • Fixed Rows Handling: If you have fixed rows that shouldn't be filtered out, adjust the visibleRowIndices logic to prepend those fixed indices to the filtered array.
  • Performance Optimization: For extremely large datasets, consider memoizing the visibleRowIndices calculation (using useMemo if converting to functional components, or shouldComponentUpdate for class components) to avoid unnecessary re-computations.
  • Memory Relief: By only passing rows that need to be rendered, react-virtualized won't create DOM elements for hidden rows, completely eliminating the memory overhead you were seeing.

内容的提问来源于stack exchange,提问作者pierreaurelemartin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 09:19:59