react-virtualized:MultiGrid结合CellMeasurer修改列宽后重渲染问题
I’ve run into this exact issue before—when using MultiGrid with CellMeasurer and CellMeasurerCache for variable row heights, simply calling recomputeGridSize() doesn’t cut it because the cached row heights are tied to the old column widths. Here’s a step-by-step solution that works reliably:
Key Problem Breakdown
When you adjust column widths, the existing row height cache is obsolete—cells that wrapped at the old width will now have different heights (or vice versa). MultiGrid doesn’t automatically know to invalidate this cache, so it keeps using stale row height data even after you call recomputeGridSize().
Step-by-Step Solution
Invalidate the CellMeasurerCache
First, clear all cached row heights. This forcesCellMeasurerto re-calculate heights based on the new column widths. Use theclearAll()method on your cache instance.Trigger MultiGrid to Re-calculate and Re-render
After clearing the cache, you need to tellMultiGridto refresh its layout. CombinerecomputeGridSize()(to recalculate grid dimensions) withforceUpdate()(to ensure the component re-renders and re-measures cells).
Working Code Example
import { MultiGrid, CellMeasurer, CellMeasurerCache } from 'react-virtualized'; class VariableHeightMultiGrid extends React.Component { constructor(props) { super(props); // Initialize cache with fixedWidth: false (critical for variable column widths) this.cellCache = new CellMeasurerCache({ fixedWidth: false, defaultHeight: 60, }); this.multiGridRef = React.createRef(); this.state = { columnWidths: [180, 220, 200], // Initial column widths }; } // Handler for user-initiated column width changes updateColumnWidth = (colIndex, newWidth) => { const updatedWidths = [...this.state.columnWidths]; updatedWidths[colIndex] = newWidth; this.setState({ columnWidths: updatedWidths }, () => { // Step 1: Clear all cached row heights this.cellCache.clearAll(); // Step 2: Force MultiGrid to refresh layout if (this.multiGridRef.current) { this.multiGridRef.current.recomputeGridSize(); this.multiGridRef.current.forceUpdate(); } }); }; render() { const { columnWidths } = this.state; return ( <MultiGrid ref={this.multiGridRef} // Your other MultiGrid props (rowCount, columnCount, etc.) columnWidth={({ index }) => columnWidths[index]} rowHeight={({ index }) => this.cellCache.get(index)} cellRenderer={({ columnIndex, rowIndex, style, parent }) => ( <CellMeasurer cache={this.cellCache} columnIndex={columnIndex} rowIndex={rowIndex} parent={parent} key={`cell-${rowIndex}-${columnIndex}`} > {({ measure, registerChild }) => ( <div ref={registerChild} style={style} // Ensure measurement runs after content loads/renders onLoad={measure} onResize={measure} > {/* Your dynamic cell content here */} </div> )} </CellMeasurer> )} /> ); } }
Critical Notes
- Set
fixedWidth: falsein CellMeasurerCache: This tells the cache that row heights can change based on column width adjustments, so it won’t treat cached heights as permanent for a given row. - Pair
recomputeGridSize()withforceUpdate():recomputeGridSize()updates the grid’s internal layout calculations, whileforceUpdate()ensures the component re-renders, givingCellMeasurera chance to re-measure each cell’s height with the new column widths. - Optimize cache invalidation (optional): If you know only specific rows are affected by the column width change, you can use
cellCache.clear(rowIndex)instead ofclearAll()to avoid unnecessary re-measurements. This is more complex but can improve performance for large grids.
内容的提问来源于stack exchange,提问作者Pete Moss

