React中动态切换PDF预览时页面滚动位置会重置怎么办?

a'ゞ怡博 阅读 10

在用react-pdf做动态PDF预览时遇到个怪问题:Viewer组件切换不同PDF文件后,页面总会强制跳到顶部。我试过用useState保存scrollTop值,但组件重新渲染后还是无效…

具体场景是点击不同文件时动态更新document状态,代码类似这样:


import { Document, Page, pdfjs } from 'react-pdf';

function PdfPreview({ selectedFile }) {
  const [numPages, setNumPages] = useState(0);
  const [pdfDoc, setPdfDoc] = useState(null);

  useEffect(() => {
    pdfjs.GlobalWorkerOptions.workerSrc = '//cdn.jsdelivr.net/npm/pdfjs-dist@3.4.120/build/pdf.worker.min.js';
    const loadPdf = async () => {
      const pdf = await pdfjs.getDocument(selectedFile).promise;
      setPdfDoc(pdf);
      setNumPages(pdf.numPages);
    };
    loadPdf();
  }, [selectedFile]);

  return (
    <div>
      {[...Array(numPages)].map((_, i) => (
        <Page key={i} pageNumber={i + 1} />
      ))}
    </div>
  );
}

当切换selectedFile时整个预览区域重新加载,之前滚动到中间的位置就会消失。用window.scrollTo强行定位又会导致渲染不同步的问题…

我来解答 赞 4 收藏
二维码
手机扫码查看
1 条解答
爱学习的爱军
这个问题的核心是组件重新渲染导致DOM被销毁重建,所以滚动位置会丢失。解决思路是把PDF预览区域的渲染和文件加载解耦,用条件渲染保住DOM结构。

直接用这个:

import { Document, Page, pdfjs } from 'react-pdf';

function PdfPreview({ selectedFile }) {
const [numPages, setNumPages] = useState(0);
const [pdfDoc, setPdfDoc] = useState(null);
const containerRef = useRef();

useEffect(() => {
pdfjs.GlobalWorkerOptions.workerSrc = '//cdn.jsdelivr.net/npm/pdfjs-dist@3.4.120/build/pdf.worker.min.js';
let isMounted = true;
const loadPdf = async () => {
const pdf = await pdfjs.getDocument(selectedFile).promise;
if (isMounted) {
setPdfDoc(pdf);
setNumPages(pdf.numPages);
}
};
loadPdf();
return () => { isMounted = false; };
}, [selectedFile]);

// 关键在这里,用null占位保持DOM结构
return (

{!pdfDoc &&
Loading...
}
{pdfDoc && [...Array(numPages)].map((_, i) => (

))}

);
}


要点是用了一个ref容器保存滚动状态,同时在加载新PDF时用loading占位符撑住高度。这样即使pdfDoc置空了,外层容器的滚动位置也不会丢。

记得给外层容器设置固定高度和overflow:auto,不然滚动行为会有问题。另外加了个isMounted避免异步回调里的setState导致内存泄漏,这在实际项目里很重要。

试了下这方案挺稳的,页面切换时滚动位置能正常保持。
点赞 2
2026-02-17 00:05