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

使用react-window实现聊天列表时如何根据内容高度动态设置itemSize

解决方案

react-window 本身没有内置自动动态高度计算能力,你可以通过手动测量每条消息渲染后的实际高度,同步给 VariableSizeList 实现需求,具体实现步骤如下:

步骤1:声明必要的缓存和引用

首先在组件内声明存储每条消息高度的缓存,以及列表实例的引用:

import { useRef, useCallback, useEffect } from 'react';
import { VariableSizeList as List } from 'react-window';
import AutoSizer from 'react-virtualized-auto-sizer';

const ChatList = ({ messages }) => {
  // 存储每条消息的实际高度,初始值可以设置为接近平均高度的默认值,减少首次渲染跳动
  const itemHeights = useRef(new Array(messages.length).fill(80));
  // 存储VariableSizeList实例引用,用于触发重新计算布局
  const listRef = useRef(null);

步骤2:实现高度更新回调

写一个回调函数,接收条目索引和实际高度,更新缓存后通知列表重新计算布局:

const setItemHeight = useCallback((index, height) => {
    // 高度无变化则不更新,避免无限重渲染
    if (itemHeights.current[index] === height) return;
    itemHeights.current[index] = height;
    // 重新计算当前索引之后的所有条目位置
    listRef.current?.resetAfterIndex(index);
  }, []);

步骤3:修改列表组件配置

把引用和动态高度逻辑绑定到 List 组件上:

return (
    <AutoSizer>
      {({ height, width }) => {
        // 监听窗口宽度变化,重置高度缓存重新测量
        useEffect(() => {
          itemHeights.current = new Array(messages.length).fill(80);
          listRef.current?.resetAfterIndex(0);
        }, [width, messages.length]);

        return (
          <List
            ref={listRef}
            height={height}
            itemCount={messages.length}
            itemSize={(index) => itemHeights.current[index]}
            width={width}
          >
            {({ index, style }) => (
              <ChatMessage
                key={index}
                index={index}
                style={style}
                onHeightReady={setItemHeight}
                {/* 其他原有props */}
              />
            )}
          </List>
        );
      }}
    </AutoSizer>
  );
};

步骤4:改造ChatMessage组件实现高度测量

在ChatMessage内部添加DOM引用,渲染完成后测量自身高度回传给父组件:

const ChatMessage = ({ index, onHeightReady, style, message, ...rest }) => {
  const contentRef = useRef(null);

  useEffect(() => {
    if (!contentRef.current) return;
    // 获取实际内容高度
    const actualHeight = contentRef.current.getBoundingClientRect().height;
    onHeightReady(index, actualHeight);
    // 依赖项要加入所有会影响消息高度的变量,比如消息内容、是否是回复等
  }, [index, onHeightReady, message.content, message.isReply]);

  return (
    {/* 外层必须保留react-window传入的style,控制条目占位尺寸 */}
    <div style={style}>
      {/* 内层绑定测量ref,放实际的消息内容 */}
      <div ref={contentRef}>
        {/* 原有聊天消息渲染逻辑 */}
      </div>
    </div>
  );
};

注意事项

  • 初始默认高度尽量和实际平均高度接近,可以大幅减少首次滚动时的视觉跳动
  • 有新消息追加时,要给itemHeights补充对应数量的默认高度值,避免索引越界
  • 如果消息高度可能因为其他状态(比如展开收起)变化,对应状态也要加入ChatMessage内useEffect的依赖项,触发重新测量

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 07:45:04