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

react-window VariableSizeList修改PDF缩放后scrollTo失效,如何解决?

问题:react-window VariableSizeList缩放后scrollTo不生效

我使用react-window的VariableSizeList组件实现滚动到指定偏移量的功能:用户修改PDF缩放比例时,派发新的缩放值,同时刷新VariableSizeList并滚动到新的偏移位置。但目前遇到问题:修改PDF缩放后调用scrollTo无法跳转到指定位置,按钮点击触发scrollTo却能正常生效。推测是VariableSizeList的渲染为异步操作,需要在渲染完成后再调用scrollTo。当前用setTimeout延迟1秒触发滚动,想找更优解决方案。

现有代码

监听缩放变化的useEffect逻辑

React.useEffect(() => {
      if (projAttr.pdfScale === 1 && cachedScale) {
        return;
      }
      setProjAttribute(projAttr);
      if (virtualListRef.current) {
        virtualListRef.current.resetAfterIndex(0, true);
        let curOffset = getCurPdfScrollOffset(projId, viewModel);
        let fullScreenOffset = getNewScaleOffsetPosition(
          projAttr.legacyPdfScale,
          projAttr.pdfScale,
          curOffset
        );
        if (fullScreenOffset) {
          setDocLoadTime();
          console.log("get the newOffset:" + fullScreenOffset);
          scrollToOffset(fullScreenOffset, virtualListRef);
          setCurPdfScrollOffset(
            fullScreenOffset,
            projId,
            viewModel,
            "project attribute update"
          );
        }
      }
    }, [projAttr, cachedScale]);

滚动到指定偏移量的方法

if (virtualListRef.current) {
    console.warn("trigger scrolltooffset:" + offset);
    virtualListRef.current.scrollTo(offset);
  }

解决方案

方案1:使用requestAnimationFrame替代setTimeout

requestAnimationFrame会在浏览器下一次重绘前执行代码,能确保VariableSizeList完成尺寸重计算后再触发滚动,比固定延迟更可靠:

// 修改useEffect中调用scrollToOffset的部分
if (fullScreenOffset) {
  setDocLoadTime();
  console.log("get the newOffset:" + fullScreenOffset);
  // 用requestAnimationFrame包裹滚动逻辑
  requestAnimationFrame(() => {
    scrollToOffset(fullScreenOffset, virtualListRef);
  });
  setCurPdfScrollOffset(
    fullScreenOffset,
    projId,
    viewModel,
    "project attribute update"
  );
}

方案2:利用React状态触发二次渲染执行滚动

通过新增状态标记需要滚动的偏移量,在组件完成重绘后再执行scrollTo:

  1. 新增状态:
const [pendingScrollOffset, setPendingScrollOffset] = React.useState(null);
  1. 修改原useEffect,将滚动偏移量存入状态:
React.useEffect(() => {
  if (projAttr.pdfScale === 1 && cachedScale) {
    return;
  }
  setProjAttribute(projAttr);
  if (virtualListRef.current) {
    virtualListRef.current.resetAfterIndex(0, true);
    let curOffset = getCurPdfScrollOffset(projId, viewModel);
    let fullScreenOffset = getNewScaleOffsetPosition(
      projAttr.legacyPdfScale,
      projAttr.pdfScale,
      curOffset
    );
    if (fullScreenOffset) {
      setDocLoadTime();
      console.log("get the newOffset:" + fullScreenOffset);
      // 存入待滚动的偏移量
      setPendingScrollOffset(fullScreenOffset);
      setCurPdfScrollOffset(
        fullScreenOffset,
        projId,
        viewModel,
        "project attribute update"
      );
    }
  }
}, [projAttr, cachedScale]);
  1. 新增useEffect监听状态变化,执行滚动:
React.useEffect(() => {
  if (pendingScrollOffset && virtualListRef.current) {
    scrollToOffset(pendingScrollOffset, virtualListRef);
    // 重置状态,避免重复触发
    setPendingScrollOffset(null);
  }
}, [pendingScrollOffset, virtualListRef]);

这两种方案都能精准等待VariableSizeList完成渲染更新,避免不必要的延迟,比setTimeout更稳定。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 15:35:58