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

如何通知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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 19:25:23