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:
- 新增状态:
const [pendingScrollOffset, setPendingScrollOffset] = React.useState(null);
- 修改原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]);
- 新增useEffect监听状态变化,执行滚动:
React.useEffect(() => { if (pendingScrollOffset && virtualListRef.current) { scrollToOffset(pendingScrollOffset, virtualListRef); // 重置状态,避免重复触发 setPendingScrollOffset(null); } }, [pendingScrollOffset, virtualListRef]);
这两种方案都能精准等待VariableSizeList完成渲染更新,避免不必要的延迟,比setTimeout更稳定。
内容的提问来源于stack exchange,提问作者Dolphin
相关产品推荐
相关产品推荐

