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

