React-pdf在Syncfusion Tab中已加载却仍显示加载状态的问题
问题描述
我使用Syncfusion Tab组件实现标签页切换展示多种类型文件,其中PDF文件通过react-pdf组件渲染。通过useQuery从服务器数据库获取文件(可在控制台打印文件内容),但切换标签页时会重新触发查询并清空文件,且Tab组件内的react-pdf始终卡在加载状态。单独使用react-pdf搭配按钮触发useQuery可正常显示PDF,集成到Tab组件中则失效。
相关代码
useQuery 代码
const { status, data, error, isFetching, refetch } = useQuery(['facture', id], async () => { const data = await getUniqueCassandraFile(id) setFile(data.rows[0].file) return data.rows[0].file }, { enabled: false, refetchOnWindowFocus: false })
renderPdf 函数
export const renderPdf = (id, file) => { if(!file){ return waiting(id) } return ( <div key={id} className='file_container'> <Document file={`data:application/pdf;base64,${file}`} style={{height:50+'vh'}}> <Page size="A4" pageNumber={1} className="pdfFacture"> </Page> </Document> </div> ) }
TabComponent 代码
<div className="control-section tab-control-section"> {chosenItem === -1 ? emptyDiv : <TabComponent overflowMode="Scrollable" id="defaultTab" selecting={selecting} selectedItem={chosenItem}> <TabItemsDirective> { header.map((item, index) => { return <TabItemDirective presentation={true} key={index} header={item} content={{ template: tabContent, data: {content: content[index], type: item.type, id: item.id}}}/> }) } </TabItemsDirective> </TabComponent> } </div>
TabContent 模板
const tabContent = (data) => { return <div dangerouslySetInnerHTML={{__html: ReactDOMServer.renderToStaticMarkup( isFetching ? emptyDiv : switchRender(data.id, data.type, file))}}> </div>; };
问题原因及解决方案
核心原因
- 静态HTML渲染破坏动态组件逻辑:
react-pdf的Document和Page依赖React生命周期和DOM动态更新,但renderToStaticMarkup将组件转为静态HTML字符串,丢失了动态交互能力,导致PDF无法完成加载。 - 状态不同步与组件重置:切换标签页时,Tab组件可能卸载/重挂载内容,加上
useQuery的触发逻辑,导致file状态被清空,而静态HTML无法响应状态变化。
修复步骤
1. 移除静态HTML转换逻辑
直接在Tab内容模板返回React组件,让react-pdf参与正常渲染流程:
const tabContent = (data) => { return isFetching ? emptyDiv : switchRender(data.id, data.type, file); };
2. 优化useQuery状态管理
去掉额外的setFile,直接使用useQuery返回的data,避免状态不同步:
const { status, data, error, isFetching, refetch } = useQuery(['facture', id], async () => { const res = await getUniqueCassandraFile(id); return res.rows[0].file; }, { enabled: false, refetchOnWindowFocus: false }); // 渲染时直接使用data:renderPdf(id, data)
3. 控制Tab内容的查询触发
在selecting回调中仅触发当前激活标签页的refetch,避免切换时无意义的状态重置:
const selecting = (args) => { const targetTabId = header[args.selectedIndex].id; // 调用对应id的refetch refetch({ id: targetTabId }); };
4. 确保react-pdf响应文件更新
修改renderPdf的key,让文件变化时组件重新挂载,触发PDF重新加载:
export const renderPdf = (id, file) => { if(!file){ return waiting(id) } // 用文件内容片段作为key的一部分,确保文件更新时组件重建 return ( <div key={`pdf-${id}-${file.slice(0, 10)}`} className='file_container'> <Document file={`data:application/pdf;base64,${file}`} style={{height: '50vh'}}> <Page size="A4" pageNumber={1} className="pdfFacture" /> </Document> </div> ) }
内容的提问来源于stack exchange,提问作者Andy Cotpi
相关产品推荐
相关产品推荐

