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

React.memo组件中PDF URL变更时未重新渲染的问题排查

React.memo 配合 react-pdf 组件不更新的问题修复

问题描述

使用 react-pdf 渲染PDF文件时,尝试通过 React.memo 控制仅当PDF URL变化时重新渲染组件,但点击按钮切换URL后,组件从未更新,无法加载新的PDF文件。

问题原因分析

  1. React.memo 比较函数逻辑颠倒:React.memo 的第二个参数返回 true 表示不需要重新渲染,返回 false 才需要重新渲染。当前代码中返回的是 prevProps.curPdfUrl !== nextProps.curPdfUrl,即URL变化时告诉React不要重新渲染,完全搞反了逻辑。
  2. 固定渲染单页PDF:renderPages 始终传入固定值 1,且未通过 Document 的 onLoadSuccess 获取实际PDF总页数,导致页面数量不会随新PDF变化。
  3. 初始状态空值(次要):Home组件中 pdfUrl 初始为空字符串,第一次点击按钮前App组件无有效内容可渲染。

修复步骤

1. 修正 React.memo 比较函数逻辑

将比较函数返回值取反,当URL相同时返回 true(不重新渲染),URL不同时返回 false(触发重新渲染):

}, (prevProps, nextProps) => {
  // URL相同则不重新渲染,不同则重新渲染
  return prevProps.curPdfUrl === nextProps.curPdfUrl;
})

2. 动态获取并渲染PDF总页数

在App组件中添加状态保存总页数,通过 Document 的 onLoadSuccess 回调更新页数:

// 新增状态保存总页数
const [totalPages, setTotalPages] = useState<number>(0);

// 更新onLoadSuccess回调
const docuemtLocadSuccess = (pdf: DocumentCallback) => {
  setTotalPages(pdf.numPages);
}

// 修改Document子组件调用,传入实际总页数
<Document options={options}
  file={curPdfUrl}
  onLoadSuccess={docuemtLocadSuccess}>
  {renderPages(totalPages)}
</Document>

3. 修复options中的httpHeaders错误(可选)

当前代码中 "getAccessToken()" 是字符串而非函数调用,需替换为实际的token获取逻辑:

httpHeaders: {
  'Authorization': 'Bearer ' + getAccessToken() // 替换为你的token获取函数
}

4. 优化初始状态(可选)

给Home组件的 pdfUrl 设置初始有效URL,避免首次点击前无内容渲染:

const [pdfUrl, setPdfUrl] = useState<string>("https://pdf.top/tex/static/proj/2023/9/287ea73d1c78463298e9e5b267cab87f/main.pdf?v=ba9e5b5fda754e72a20");

修改后的完整App.tsx代码

import React, { useRef, useState } from 'react';
import { Page, Document } from 'react-pdf';
import { DocumentCallback, Options, PageCallback } from 'react-pdf/dist/cjs/shared/types';
import { pdfjs } from 'react-pdf';
import 'react-pdf/dist/Page/TextLayer.css';
import styles from './App.module.css';

pdfjs.GlobalWorkerOptions.workerSrc = `//unpkg.com/pdfjs-dist@${pdfjs.version}/build/pdf.worker.min.js`;

interface PDFPreviewProps {
  curPdfUrl: string;
}

const App: React.FC<PDFPreviewProps> = React.memo(({ curPdfUrl }) => {
  const [totalPages, setTotalPages] = useState<number>(0);
  const canvasArray = useRef<Array<React.MutableRefObject<HTMLCanvasElement | null>>>([]);

  const handlePageRenderSuccess = (page: PageCallback) => {};

  const options: Options = {
    cMapUrl: `https://cdn.jsdelivr.net/npm/pdfjs-dist@${pdfjs.version}/cmaps/`,
    httpHeaders: {
      'Authorization': 'Bearer ' + getAccessToken() // 替换为实际的token获取逻辑
    }
  };

  const docuemtLocadSuccess = (pdf: DocumentCallback) => {
    setTotalPages(pdf.numPages);
  };

  const updateRefArray = (index: number, element: HTMLCanvasElement | null) => {
    if (element) {
      canvasArray.current[index] = { current: element };
    }
  };

  const handlePageChange = (page: any) => {};

  const renderPages = (totalPageNum: number | undefined) => {
    if (!totalPageNum || totalPageNum < 1) return null;
    const tagList: JSX.Element[] = [];
    for (let i = 1; i <= totalPageNum; i++) {
      tagList.push(
        <Page 
          key={i}
          scale={1}
          onLoad={handlePageChange}
          canvasRef={(element) => updateRefArray(i, element)}
          onChange={handlePageChange}
          onRenderSuccess={handlePageRenderSuccess}
          pageNumber={i} 
        />
      );
    }
    return tagList;
  };

  return (
    <div className={styles.container}>
      <div className={styles.rightPart}>
        <Document 
          options={options}
          file={curPdfUrl}
          onLoadSuccess={docuemtLocadSuccess}
        >
          {renderPages(totalPages)}
        </Document>
      </div>
    </div>
  );
}, (prevProps, nextProps) => {
  // URL相同时不重新渲染,不同时触发重新渲染
  return prevProps.curPdfUrl === nextProps.curPdfUrl;
});

export default App;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 05:44:50