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

react-virtualized搭配InfiniteLoader等组件路由返回后无法恢复滚动位置

解决react-virtualized配合WindowScroller的滚动位置恢复问题

你之前的方案失效的核心原因是WindowScroller组件会接管List的滚动状态,你直接给List传scrollTop或者调用List的滚动方法,都会被WindowScroller的内部状态覆盖,自然达不到预期效果。以下是可直接落地的修改方案:


具体修改步骤

1. 新增恢复状态标记

在组件内加一个状态,用来判断是否已经完成滚动位置恢复,避免和WindowScroller的默认滚动逻辑冲突:

const [isPositionRestored, setIsPositionRestored] = useState(false)

2. 修改List的scrollTop属性

调整List的scrollTop赋值逻辑,未恢复位置前优先使用你存储的positionY,恢复后交还给WindowScroller控制:

<List
  // 其他原有属性保持不变
  scrollTop={isPositionRestored ? scrollTop : positionY}
/>

3. 调整滚动恢复的触发逻辑

原来的useEffect依赖缺少数据加载完成的判断,容易出现数据还没加载、行高还没计算就触发滚动,导致位置偏移。修改如下:

useEffect(() => {
  // 确保数据加载完成、列表实例存在、有存储的滚动位置且未执行过恢复操作时再触发
  if (listRef.current && positionY !== 0 && data.length > 0 && !isPositionRestored) {
    // 先重算所有行高,避免CellMeasurer缓存的旧高度导致滚动位置不准
    listRef.current.recomputeRowHeights()
    // 标记恢复完成,后续滚动由WindowScroller接管
    setIsPositionRestored(true)
  }
}, [data, positionY, isPositionRestored])

4. 重置恢复标记

在页面卸载的清理逻辑中,重置恢复标记,保证下次进入页面可以重新触发恢复:

useEffect(() => {
  if (data.length === 0) {
    // 原有API调用逻辑
  }
  return () => {
    const position = window.pageYOffset
    setPosition(position)
    // 新增重置逻辑
    setIsPositionRestored(false)
    // 如果你的CellMeasurerCache是全局定义的,建议这里加一行清理缓存:cache.clearAll()
  }
}, [])

备选方案

如果上述方案仍有问题,可以直接操作WindowScroller实例的滚动方法:

  • 给WindowScroller加ref:const windowScrollerRef = useRef()
  • 组件内使用时绑定ref:<WindowScroller ref={windowScrollerRef}>
  • 恢复位置时调用:windowScrollerRef.current?.scrollToPosition(positionY)

注意事项

你当前定义的CellMeasurerCache如果是写在组件外部的全局实例,切换页面后缓存的旧行高会导致滚动位置计算错误,建议要么把cache定义在组件内部,要么每次页面卸载时调用cache.clearAll()清理缓存,该方案兼容你正在使用的9.19.1版本react-virtualized。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 01:15:05