如何通知react-virtualized List组件行高变化并触发重渲染?
问题解决:react-virtualized List行高动态更新后重渲染
问题
使用react-virtualized的List组件,每行带有展开按钮,点击后行高变化并展示更多内容,但点击后内部Grid的高度未更新,也未触发重渲染,导致内容被遮挡或布局错乱。
解决方案
核心是利用CellMeasurer和CellMeasurerCache来动态计算并缓存行高,同时为每行维护独立的展开状态,触发更新时通知List重新计算。
修改后的代码
index.js
import React, { useRef, useState } from "react"; import { List, AutoSizer, CellMeasurer, CellMeasurerCache } from "react-virtualized"; import Expander from "./expander.js"; export default function Test() { // 存储每行的展开状态,key为行索引 const [expandedRows, setExpandedRows] = useState({}); // 创建缓存实例,默认行高30,固定宽度模式 const cache = useRef( new CellMeasurerCache({ defaultHeight: 30, fixedWidth: true }) ).current; // 处理展开/收起事件 const handleExpandChange = (index) => { // 切换当前行的展开状态 setExpandedRows(prevState => ({ ...prevState, [index]: !prevState[index] })); // 清除当前行的高度缓存,触发重新测量 cache.clear(index); // 通知List组件更新网格布局 listRef.current?.forceUpdateGrid(); }; const listRef = useRef(); const listData = [ "Brian Vaughn", "Bob Smith", "Someone Else", "I hate making up names" ]; return ( <div> <AutoSizer> {({ width, height }) => ( <List ref={listRef} className="List" width={800} height={400} rowCount={listData.length} // 使用缓存提供的动态行高方法 rowHeight={cache.rowHeight} rowRenderer={({ index, key, style, parent }) => ( <CellMeasurer key={key} cache={cache} parent={parent} rowIndex={index} columnIndex={0} > {({ measure, registerChild }) => ( <div ref={registerChild} className="Row" style={style} > {listData[index]} <Expander isExpanded={!!expandedRows[index]} onChanged={() => handleExpandChange(index)} /> </div> )} </CellMeasurer> )} /> )} </AutoSizer> </div> ); }
expander.js
import React from "react"; export default function Expander({ isExpanded, onChanged }) { const renderMoreContent = () => { if (isExpanded) { return ( <div style={{ backgroundColor: "red", height: 200 }}> long lorem ipsum </div> ); } return null; }; return ( <div> <button onClick={onChanged}> {isExpanded ? "收起" : "展开更多内容"} </button> {renderMoreContent()} </div> ); }
关键说明
- CellMeasurerCache:负责缓存每行的高度,当行内容变化时,调用
clear(index)清除对应行的缓存,让CellMeasurer重新计算实际高度。 - 独立展开状态:用
expandedRows对象存储每行的展开状态,避免所有行共用同一个状态导致的混乱。 - forceUpdateGrid:在缓存清除后调用,触发List组件重新计算行高并更新网格布局,确保内部Grid的高度正确更新。
- CellMeasurer:包裹每行元素,通过
registerChild注册要测量的DOM节点,measure方法负责计算高度并更新缓存。
内容的提问来源于stack exchange,提问作者yeln
相关产品推荐
相关产品推荐

