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

Portal模态框中react-pdf-viewer的initialPage传参失效问题

问题根本原因
  • 首先排除React Portal的影响:Portal仅修改最终DOM的挂载位置,组件的props传递、上下文、生命周期逻辑和普通嵌套子组件完全一致,不会因为DOM挂在#root外部就出现传值异常。
  • 真正导致initialPage不生效的核心原因有2个:
    1. defaultLayoutPlugin()被直接写在组件函数渲染体内,每次组件重渲染(比如open状态切换、父组件重渲染)都会生成全新的插件实例,会触发Viewer内部状态重置,覆盖初始化时读取的initialPage值,最终回到默认第0页。
    2. initialPage本身是Viewer的一次性初始化属性,仅在组件首次挂载时读取一次,对后续的props变化无响应;如果存在PDF加载时序问题(比如worker加载、文档流加载完成晚于组件首次挂载),就算首次传值正确,也可能出现页码不生效的问题。
  • 额外注意:react-pdf-viewer的页码是0起始索引,传入5实际对应PDF的第6页,需要和你实际文章的页码做对齐。
修复方案

不要只依赖initialPage做初始化,做两层保障:

  1. 用useMemo缓存布局插件实例,避免每次渲染生成新实例导致Viewer异常重置
  2. 监听PDF文档加载完成事件,主动调用跳转API定位到目标页码,彻底规避初始化时序问题

修复后的PDFModal组件代码如下:

import { useState, useMemo, useEffect } from 'react';
import { Worker, Viewer, SpecialZoomLevel } from '@react-pdf-viewer/core';
import { defaultLayoutPlugin } from '@react-pdf-viewer/default-layout';
import * as ReactDom from 'react-dom';

// 按项目实际路径引入对应样式
import '@react-pdf-viewer/core/lib/styles/index.css';
import '@react-pdf-viewer/default-layout/lib/styles/index.css';

export default function PDFModal({ fileUrl, open, onClose, startPage }) {
  // 缓存插件实例,仅组件初始化时生成一次
  const defaultLayoutPluginInstance = useMemo(() => defaultLayoutPlugin(), []);
  // 存储PDF跳转方法
  const [jumpToPage, setJumpToPage] = useState(null);

  useEffect(() => {
    // 模态框打开、跳转方法和目标页码都就绪时,主动执行跳转
    if (open && jumpToPage && typeof startPage === 'number') {
      // 如果业务侧页码从1开始计数,这里改为 jumpToPage(startPage - 1) 即可
      jumpToPage(startPage);
    }
  }, [open, jumpToPage, startPage]);

  if (!open) return null;

  return ReactDom.createPortal(
    <>
      <div style={OVERLAY_STYLES} />
      <div style={MODAL_STYLES}>
        <button style={BUTTON_STYLES} onClick={onClose}>
          Close
        </button>

        <Worker workerUrl="https://unpkg.com/pdfjs-dist@2.14.305/build/pdf.worker.min.js">
          <Viewer
            fileUrl={fileUrl}
            plugins={[defaultLayoutPluginInstance]}
            defaultScale={SpecialZoomLevel.ActualSize}
            initialPage={startPage}
            onDocumentLoad={(e) => {
              // 文档加载完成后存储跳转方法
              setJumpToPage(() => e.jumpToPage);
            }}
          />
        </Worker>
      </div>
    </>,
    document.getElementById("PDFModal")
  );
}

父组件Articles页面的代码、Portal挂载逻辑都不需要做额外调整。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 03:45:33