如何在Remix Run中生成PDF时禁用资源路由Link并后续启用?
解决Remix Run PDF下载按钮的禁用/启用问题
核心思路
放弃使用带reloadDocument的<Link>,改用手动发起请求的方式,全程控制请求状态并处理文件下载,以此实现按钮的禁用与自动恢复。
具体实现步骤
1. 替换<Link>为可控按钮
用普通<button>替代<Link>,通过useState管理按钮禁用状态,点击时触发下载逻辑:
import { useState } from "react"; export default function ReportPage() { const [isDownloading, setIsDownloading] = useState(false); const handleDownload = async () => { setIsDownloading(true); try { // 发起请求获取PDF流 const response = await fetch("/pdf-report"); if (!response.ok) throw new Error("PDF生成失败"); // 处理文件下载流程 const blob = await response.blob(); const url = window.URL.createObjectURL(blob); const downloadLink = document.createElement("a"); downloadLink.href = url; downloadLink.download = "report.pdf"; // 匹配资源路由设置的文件名 document.body.appendChild(downloadLink); downloadLink.click(); window.URL.revokeObjectURL(url); document.body.removeChild(downloadLink); } catch (err) { console.error(err); // 可在此添加错误提示逻辑 } finally { // 无论成功/失败/用户取消保存,都恢复按钮状态 setIsDownloading(false); } }; return ( <button onClick={handleDownload} disabled={isDownloading} style={{ pointerEvents: isDownloading ? "none" : "auto" }} > {isDownloading ? "生成中..." : "下载PDF报告"} </button> ); }
2. 保留原有资源路由逻辑
你的PDF资源路由(如app/routes/pdf-report.tsx)无需修改,继续返回ReadableStream并设置响应头:
import type { LoaderFunctionArgs } from "@remix-run/node"; import { createPdfStream } from "your-pdf-library"; // 你的PDF生成工具 export async function loader({ request }: LoaderFunctionArgs) { const pdfStream = await createPdfStream(); // 执行PDF生成逻辑 return new Response(pdfStream, { headers: { "Content-Type": "application/pdf", "Content-Disposition": 'attachment; filename="report.pdf"', }, }); }
方案优势
- 脱离
reloadDocument的限制,通过fetch全程掌控请求生命周期,精准控制按钮状态。 - 无论PDF生成成功、失败,还是用户取消保存弹窗,
finally块都会执行,确保按钮恢复可用。 - 无需依赖Remix路由跳转机制,纯前端逻辑即可完成下载与状态管理。
内容的提问来源于stack exchange,提问作者mogarick
相关产品推荐
相关产品推荐

