虚拟滚动列表在React中渲染空白,是哪里出错了?

打工人爱慧 阅读 56

我在用React实现一个长列表的虚拟滚动,数据有上万条,但页面只显示空白,滚动也没反应。我参考了网上的例子,用了固定高度和transform定位,但就是不渲染内容。

控制台没报错,数据也正常加载了,是不是我的计算逻辑有问题?下面是我的简化代码:

const VirtualList = ({ items, itemHeight = 50 }) => {
  const containerHeight = 600;
  const [scrollTop, setScrollTop] = useState(0);
  const visibleCount = Math.ceil(containerHeight / itemHeight);
  const startIdx = Math.floor(scrollTop / itemHeight);
  const visibleItems = items.slice(startIdx, startIdx + visibleCount);

  return (
    <div onScroll={(e) => setScrollTop(e.target.scrollTop)} style={{ height: containerHeight, overflow: 'auto' }}>
      <div style={{ height: items.length * itemHeight }} />
      {visibleItems.map((item, i) => (
        <div key={startIdx + i} style={{ height: itemHeight, transform: <code>translateY(${(startIdx + i) * itemHeight}px)</code> }}>
          {item.name}
        </div>
      ))}
    </div>
  );
};
我来解答 赞 8 收藏
二维码
手机扫码查看
2 条解答
UI新艳
UI新艳 Lv1
我看了你的代码,问题主要出在transform定位和列表渲染的逻辑上。首先你用的这个 translateY 方式不太对,会导致元素重叠或错位。

建议直接用position: absolute来定位每个可见项,这样更直观可控。还有个关键点是需要一个外层容器来包裹这些绝对定位的元素,给它设置相对定位。

给你改了一下代码:

const VirtualList = ({ items, itemHeight = 50 }) => {
const containerHeight = 600;
const [scrollTop, setScrollTop] = useState(0);
const visibleCount = Math.ceil(containerHeight / itemHeight);
const startIdx = Math.floor(scrollTop / itemHeight);
const visibleItems = items.slice(startIdx, startIdx + visibleCount);

return (
<div onScroll={(e) => setScrollTop(e.target.scrollTop)} style={{ height: containerHeight, overflow: 'auto', position: 'relative' }}>
{visibleItems.map((item, i) => (
<div key={startIdx + i} style={{
position: 'absolute',
top: (startIdx + i) * itemHeight,
height: itemHeight
}}>
{item.name}
</div>
))}
</div>
);
};


我之前也碰到过类似的问题,调试了好几个小时才搞明白。记得检查下容器的高度和滚动条是否正常显示,有时候小细节也会导致大问题。希望这个修改对你有帮助!
点赞
2026-03-30 10:08
浩然
浩然 Lv1
问题在于你的visibleItems没有放在一个相对定位的容器里,translateY定位基准错了。最简单的办法:给包裹visibleItems的div加上position: relative。

const VirtualList = ({ items, itemHeight = 50 }) => {
const containerHeight = 600;
const [scrollTop, setScrollTop] = useState(0);
const visibleCount = Math.ceil(containerHeight / itemHeight);
const startIdx = Math.floor(scrollTop / itemHeight);
const visibleItems = items.slice(startIdx, startIdx + visibleCount);

return (
setScrollTop(e.target.scrollTop)} style={{ height: containerHeight, overflow: 'auto', position: 'relative' }}>


{visibleItems.map((item, i) => (

{item.name}

))}


);
};


改成绝对定位比transform更省事,不用自己算translateY了。
点赞
2026-03-18 09:13