如何为jspdf+html2canvas添加加载Spinner?React状态更新异常求助
Hey there, I’ve run into this exact issue before—let’s break down why your spinner isn’t showing up immediately and how to fix it!
The Root Cause
React’s setState is asynchronous, and html2canvas is a resource-heavy operation that blocks the main thread. When you call setState({ isDownloading: true }) followed immediately by html2canvas, the main thread gets tied up processing the canvas conversion before React can finish updating the state and rendering your spinner. That’s why the spinner only pops up right before the PDF downloads—once the heavy work is almost done.
Solution 1: Use setState’s Callback to Delay Heavy Work
React’s setState accepts a second callback parameter that runs after the state has been updated and the component has re-rendered. This ensures your spinner is visible before html2canvas starts chugging away.
Here’s how to adjust your code:
printDocument() { const input = document.getElementById('container'); // Update state first, then run html2canvas in the callback this.setState({ isDownloading: true }, () => { html2canvas(input) .then((canvas) => { const imgData = canvas.toDataURL('image/png'); const pdf = new pdfConverter("p", "mm", "a4"); const width = pdf.internal.pageSize.width; const height = pdf.internal.pageSize.height; pdf.addImage(imgData, 'JPEG', 0, 0, width, height); pdf.save("download.pdf"); this.setState({ isDownloading: false }); }); }); }
Solution 2: Add a Tiny Delay with setTimeout (For Stubborn Cases)
If the callback alone doesn’t work (sometimes the main thread still gets blocked before rendering), wrap the html2canvas call in a setTimeout with a 0ms delay. This pushes the heavy work to the end of the browser’s event queue, giving it time to finish rendering the spinner first.
Modified code:
printDocument() { const input = document.getElementById('container'); this.setState({ isDownloading: true }, () => { // Give the browser a moment to render the spinner setTimeout(() => { html2canvas(input) .then((canvas) => { const imgData = canvas.toDataURL('image/png'); const pdf = new pdfConverter("p", "mm", "a4"); const width = pdf.internal.pageSize.width; const height = pdf.internal.pageSize.height; pdf.addImage(imgData, 'JPEG', 0, 0, width, height); pdf.save("download.pdf"); this.setState({ isDownloading: false }); }); }, 0); }); }
Bonus: Optimize Large Content (Optional)
If your page is really large, consider these extra tweaks to speed up the process:
- Exclude non-critical elements from the
inputcontainer to reduce whathtml2canvashas to process. - Adjust
html2canvasoptions likescale(lower it slightly if image quality allows) oruseCORS(if you’re loading external images) to speed up rendering. - For ultra-large content, look into chunking the PDF into multiple pages instead of rendering everything as one big canvas.
Hope this fixes your spinner issue—let me know if you run into any other snags!
内容的提问来源于stack exchange,提问作者Johnson Samuel

