如何将MUI组件转换为PDF?遇useInsertionEffect错误求助
解决方案
错误原因分析
- React版本不兼容:
useInsertionEffect是React 18新增的钩子,你的项目当前使用的React版本低于18,而@react-pdf/renderer或MUI的依赖版本要求React 18,导致报错。 - 组件混用错误:
@react-pdf/renderer有自己独立的组件体系(如内置的排版组件),不能直接将MUI的<Typography>组件放入@react-pdf的<Document>/<Page>中渲染,两者的渲染环境不兼容。
方案一:升级React版本并使用@react-pdf原生组件
1. 升级React到18
执行以下命令升级依赖:
npm install react@^18 react-dom@^18
若使用Yarn:
yarn add react@^18 react-dom@^18
2. 替换MUI组件为@react-pdf原生组件
修改PDF组件代码,使用@react-pdf/renderer内置的<Text>组件复刻MUI样式:
import { Document, Page, View, Text, StyleSheet } from '@react-pdf/renderer'; const styles = StyleSheet.create({ page: { padding: 30, }, section: { marginBottom: 10, }, heading: { fontSize: 24, // 匹配MUI h5字号 fontWeight: 'bold', }, }); const MyPdf = () => ( <Document> <Page size="A4" style={styles.page}> <View style={styles.section}> <Text style={styles.heading}>Hello World</Text> </View> </Page> </Document> );
3. 保留原打开PDF的函数
你的openPdf函数可继续使用:
import { pdf } from '@react-pdf/renderer'; async function openPdf() { const pdfBlob = await pdf(<MyPdf />).toBlob(); const pdfUrl = URL.createObjectURL(pdfBlob); const pdfWindow = window.open(pdfUrl, '_blank'); if (pdfWindow) { pdfWindow.document.title = 'My PDF Document'; } }
方案二:不升级React,降级@react-pdf版本并调整组件
若无法升级React到18,可降级@react-pdf/renderer到不依赖useInsertionEffect的版本:
1. 降级@react-pdf/renderer
npm install @react-pdf/renderer@^2.2.0
2. 调整PDF组件代码
同样使用@react-pdf原生组件复刻MUI样式:
import { Document, Page, View, Text, StyleSheet } from '@react-pdf/renderer'; const styles = StyleSheet.create({ page: { padding: 30 }, section: { marginBottom: 10 }, h5: { fontSize: 24, fontWeight: 600, // 匹配MUI h5字重 }, }); const MyPdf = () => ( <Document> <Page size="A4" style={styles.page}> <View style={styles.section}> <Text style={styles.h5}>Hello World</Text> </View> </Page> </Document> );
方案三:将MUI组件渲染为HTML后转PDF
若需完全保留MUI组件样式,可先渲染为HTML再转换:
1. 安装依赖
npm install html2canvas jspdf
2. 编写转换函数
import html2canvas from 'html2canvas'; import jsPDF from 'jspdf'; async function openPdf() { // 获取MUI组件的DOM元素(需给组件添加id) const muiElement = document.getElementById('mui-typography'); if (!muiElement) return; const canvas = await html2canvas(muiElement); const imgData = canvas.toDataURL('image/png'); const pdf = new jsPDF('p', 'mm', 'A4'); const imgWidth = 210; // A4宽度 const pageHeight = 297; const imgHeight = (canvas.height * imgWidth) / canvas.width; let heightLeft = imgHeight; let position = 0; pdf.addImage(imgData, 'PNG', 0, position, imgWidth, imgHeight); heightLeft -= pageHeight; while (heightLeft >= 0) { position = heightLeft - imgHeight; pdf.addPage(); pdf.addImage(imgData, 'PNG', 0, position, imgWidth, imgHeight); heightLeft -= pageHeight; } // 打开PDF pdf.output('blob').then(blob => { const pdfUrl = URL.createObjectURL(blob); const pdfWindow = window.open(pdfUrl, '_blank'); if (pdfWindow) { pdfWindow.document.title = 'My PDF Document'; } }); } // 带id的MUI组件 const MuiComponent = () => ( <div id="mui-typography"> <Typography component="h6" variant="h5">Hello World</Typography> </div> );
内容的提问来源于stack exchange,提问作者elegance007
相关产品推荐
相关产品推荐

