如何获取数据后以Blob形式在当前窗口打开PDF替代PDFViewer
实现方案
要替换PDFViewer,在获取接口数据后直接在当前标签页以Blob形式打开PDF,可以通过以下两种方式实现:
方式一:使用renderToBlob直接生成并跳转
这种方式无需BlobProvider,直接调用@react-pdf/renderer提供的renderToBlob方法生成PDF Blob,再通过window.location.href跳转到Blob URL。
修改后的完整代码:
import { OrderDocument } from '@/components' import { toast } from '@/components/ui/use-toast' import { useAuthContext } from '@/context/authContext' import { getFetch } from '@/hooks/fetchData' import { renderToBlob } from '@react-pdf/renderer' import { useEffect, useState } from 'react' import { ImSpinner6 } from "react-icons/im"; import { useNavigate, useParams } from 'react-router-dom' const OrderReceipt = () => { const { orderId } = useParams() const { user } = useAuthContext() const token = user?.apikey?.token const [orderData, setOrderData] = useState(); const [isLoading, setIsLoading] = useState(false); const [isError, setIsError] = useState(null); const navigate = useNavigate() useEffect(() => { setIsLoading(true) getFetch(token, `/orders/${orderId}`) .then((res) => { setOrderData(res.data?.data) }) .catch((e) => { setIsError(e?.response?.data?.message) toast({ variant: 'destructive', description: e.response.data.message, }); navigate('/') }) .finally(() => setIsLoading(false)) }, []) // 数据加载完成后生成PDF并在当前页打开 useEffect(() => { if (!orderData) return renderToBlob(<OrderDocument data={[orderData]} />) .then((blob) => { const pdfUrl = URL.createObjectURL(blob) // 替换当前页地址为PDF Blob URL window.location.href = pdfUrl // 延迟释放URL资源,避免跳转时资源被回收 setTimeout(() => URL.revokeObjectURL(pdfUrl), 1000) }) .catch(() => { toast({ variant: 'destructive', description: 'PDF生成失败,请重试', }) }) }, [orderData]) if (isLoading) { return <div className='w-full h-screen flex-center'> <ImSpinner6 className="animate-spin text-gray-500 size-24" /> </div> } if (isError) { return <div className='w-full h-screen flex-center'> <h2>unexpected error</h2> </div> } // 数据加载完成后会立即跳转,此处无需额外渲染内容 return null } export default OrderReceipt
方式二:基于BlobProvider实现跳转
如果你更习惯使用之前的BlobProvider,可以通过在BlobProvider内部获取生成的URL,再触发当前页跳转:
替换原组件中return部分的代码即可:
return ( <> {isLoading && <div className='w-full h-screen flex-center'> <ImSpinner6 className="animate-spin text-gray-500 size-24" /> </div>} {isError && <div className='w-full h-screen flex-center'> <h2>unexpected error</h2> </div>} {orderData && ( <BlobProvider document={<OrderDocument data={[orderData]} />}> {({ url }) => { // 组件挂载后执行跳转 useEffect(() => { window.location.href = url return () => URL.revokeObjectURL(url) }, [url]) // 无需渲染可见内容 return null }} </BlobProvider> )} </> )
注意事项
- 生成Blob URL后,记得调用
URL.revokeObjectURL()释放资源,避免内存泄漏 - 若浏览器阻止自动跳转,可添加手动触发按钮,但上述方案已满足自动在当前页打开的需求
- 确保
OrderDocument组件能正确接收data并渲染PDF内容
内容的提问来源于stack exchange,提问作者abdo_me
相关产品推荐
相关产品推荐

