TLDR:为什么每次我要生成 pdf 时都会出现此错误?
app-index.js:33 TypeError: Cannot read properties of null (reading 'write')
at PDFDocument.addContent (pdfkit.browser.js:46504:15)
at PDFDocument.save (pdfkit.browser.js:9270:17)
at renderNode (index.js:1897:7)
at eval (index.js:1986:25)
at Array.forEach (<anonymous>)
at render (index.js:1986:9)
at render (react-pdf.browser.js:4249:85)
at async Object.toBlob (react-pdf.browser.js:4268:9)
有时我会收到此错误
BindingError: Expected null or instance of Config,…act-pdf/renderer/lib/react-pdf.browser.js:4268:9
我有一个多重表单,其中我使用react-hook-form,然后使用
form.watch()
,我检索它的数据并将其传递给我的appointmentdocument.tsx
,其中它为我的实际设计提供服务pdf文件
main.tsx -> downloadbutton.tsx -> pdfdownload.tsx ->appointmentdocument.tsx
那就从这里开始吧
main.tsx
<DownloadButton
form={form}
/>
下载按钮.tsx
'use client'
import dynamic from 'next/dynamic'
import React, { useEffect, useState } from 'react'
import { Loader2 } from 'lucide-react'
const PDFDownload = dynamic(
() => import('./pdf-download-component'),
{
loading: () => <Loader2 className='animate-spin' />,
ssr: false
}
)
const DownloadButton = ({ form }: any) => {
const [showButton, setShowButton] = useState(false)
useEffect(() => {
const timer = setTimeout(() => {
setShowButton(true)
}, 5000) // 3 seconds delay
return () => clearTimeout(timer) // Cleanup timer on component unmount
}, [])
return (
<>
{showButton ? (
<PDFDownload form={form} />
) : (
<>
<Loader2 className='animate-spin' />
<p>Kindly wait, we're generating your pdf copy...</p>
</>
)}
</>
)
}
export default DownloadButton
之后,我将其传递给该组件。
const PDFDownload: React.FC<PDFDownloadProps> = ({ form }) => {
return (
<BlobProvider document={<AppointmentDocument form={form} />}>
{({ blob, url, loading, error }) => {
if (loading) {
return (
<Button variant="default" className='flex gap-2' type='button' size="sm" disabled>
Loading document...
</Button>
)
}
if (error) {
return (
<Button variant="default" className='flex gap-2' type='button' size="sm" disabled>
Error loading document
</Button>
)
}
return (
<Button
variant="default"
className='flex gap-2'
type='button'
size="sm"
onClick={() => {
const link = document.createElement('a')
//@ts-ignore
link.href = url
link.download = 'Appointment_Schedule.pdf'
link.click()
}}
>
<Download />
<p>Appointment, download PDF copy</p>
</Button>
)
}}
</BlobProvider>
)
}
export default PDFDownload
然后,我再次将其传递到 AppointmentDocument.tsx,这是我处理文档类型的所有样式的地方。
import React, { useState, useEffect } from 'react';
import { Document, Page, Text, View, Image, StyleSheet, Font } from '@react-pdf/renderer';
import { Loader2 } from 'lucide-react';
// Assume these are imported correctly
import CUSTOMLOGO_1 from '@/public/sample_logo.png';
import CUSTOMLOGO2 from '@/public/logo2.png';
import { format } from 'date-fns';
// Register fonts (you'll need to provide the correct paths to your font files)
// Create styles
const styles = StyleSheet.create({
page: {
flexDirection: 'column',
backgroundColor: '#ffffff',
padding: 30,
},
header: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
marginBottom: 20,
borderBottom: '1 solid #000',
paddingBottom: 10,
},
logo: {
width: 50,
height: 50,
},
headerText: {
flexDirection: 'column',
alignItems: 'center',
flex: 1,
},
main: {
fontSize: 16,
fontWeight: 'bold',
marginBottom: 5,
},
subtitle: {
fontSize: 12,
marginBottom: 3,
},
email: {
fontSize: 10,
color: '#666',
},
//Content Main Header Date to Webinar
content: {
flexDirection: 'column',
alignItems: 'center',
flex: 1,
},
labelAnswerContent: {
flexDirection: 'row',
},
label: {
fontSize: 16,
fontWeight: 'bold'
},
labelAnswer: {
fontSize: 14,
paddingLeft: 2
}
});
const AppointmentDocument = ({ form }: any) => {
const event_date = form.watch('event_date')
const formattedDate = format(event_date, 'MMMM dd yyyy');
const [isClient, setIsClient] = useState(false);
useEffect(() => {
setIsClient(true);
}, []);
if (!isClient) {
return <Loader2 className="animate-spin" />;
}
return (
<Document>
<Page size="A4" style={styles.page}>
<View style={styles.header}>
<Image src={CUSTOMLOGO_1.src} style={styles.logo} />
<View style={styles.headerText}>
<Text style={styles.main}>Trinity University Of Asia</Text>
<Text style={styles.subtitle}>Trinitian Center for Education and Technology</Text>
<Text style={styles.email}>[email protected]</Text>
</View>
<Image src={CUSTOMLOGO2.src} style={styles.logo} />
</View>
<View >
<View>
<Text>Date of event: </Text>
<Text>{formattedDate}</Text>
</View>
</View>
</Page>
</Document>
);
};
export default AppointmentDocument
const [isClient, setIsClient] = useState(false);
useEffect(() => {
setIsClient(true);
}, []);
if (!isClient) {
return <Loader2 className="animate-spin" />;
}
在
AppointmentDocument
中,由于 Loader2
的初始状态为 false,导致错误,因此首次返回 isClient
组件。
如果您出于某种原因需要该条件,请将其移动到
PDFDownload
组件并有条件地渲染 BlobProvider
。