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

如何在react-window的VariableSizeList中实现内容适配、无重叠的行?

行重叠问题原因

你当前的代码直接给VariableSizeList固定返回了itemSize={() => 100},但列表项内包含随机长度的LoremIpsum内容,实际渲染高度可能远大于100。react-window是靠预设的itemSize计算每个元素的偏移位置的,预设高度和实际高度不符就会出现行重叠。

适配修改步骤

不需要使用未正式发布的DynamicSizeList,仅基于现有VariableSizeList加少量逻辑即可实现自适应高度,修改点如下:

1. 新增状态存储行高、列表实例引用

// 原有状态保留,新增以下两个状态
const [rowHeights, setRowHeights] = useState([]);
const listRef = useRef(null);

2. 新增更新行高的工具方法

// 计算并更新指定行的实际高度
const setRowHeight = useCallback((index, height) => {
  setRowHeights(prev => {
    if (prev[index] === height) return prev;
    const newHeights = [...prev];
    newHeights[index] = height;
    // 通知列表重新计算该位置之后的所有元素偏移
    listRef.current?.resetAfterIndex(index);
    return newHeights;
  });
}, []);

3. 加载新数据时同步初始化行高默认值

修改你的_loadNextPage方法,加载到新数据时给rowHeights追加对应数量的默认高度,同时删掉你代码里axios请求外多余的setIsNextPageLoading(false)(异步请求外直接关加载状态是错误写法):

const _loadNextPage = (...args) => {
  setIsNextPageLoading(true);
  setHasNextPage(items.length < 100);

  axios
    .get(
      `https://randomuser.me/api/?results=5&page=1&inc=name,gender,email,nat&noinfo`
    )
    .then((response) => {
      const newItems = response.data.results;
      setItems(prev => [...prev, ...newItems]);
      // 给新增的5行初始化默认高度
      setRowHeights(prev => [...prev, ...new Array(newItems.length).fill(100)]);
      setIsNextPageLoading(false);
    })
    .catch((error) => {
      setIsNextPageLoading(false);
      console.error("Error:", error);
    });
  // 删掉这里原来的setIsNextPageLoading(false)
};

4. 修改Item组件,渲染后获取实际高度

const Item = ({ index, style }) => {
  const itemRef = useRef(null);

  useLayoutEffect(() => {
    if (itemRef.current) {
      setRowHeight(index, itemRef.current.offsetHeight);
    }
  }, [index, setRowHeight]);

  const content = !isItemLoaded(index) ? (
    "Loading..."
  ) : (
    <div style={{ display: "flex" }}>
      <div>{index}</div>
      <div>{items[index].email}</div>
      <div>
        <LoremIpsum random={true} />
      </div>
    </div>
  );

  return (
    <div ref={itemRef} key={index} style={style}>
      {content}
    </div>
  );
};

5. 修改List组件的配置

给List绑定ref,把itemSize改成从rowHeights取值:

<List
  className="List"
  height={height}
  itemCount={itemCount}
  itemSize={index => rowHeights[index] || 100} // 未获取到实际高度时用默认值
  onItemsRendered={onItemsRendered}
  ref={listRef} // 绑定列表实例ref
  width={width}
>
  {Item}
</List>
注意事项
  • 如果你的列表内容后续会动态更新,在内容更新的回调里重新调用setRowHeight更新对应行的高度即可
  • 加载中的提示行如果高度固定,你可以单独给它设置特殊的高度逻辑,避免重复计算
  • 不要在setRowHeight里做不必要的更新,已存在且和实际高度一致的值不要重复触发状态更新,避免性能问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 13:12:02