diegomura / react-pdf

📄 Create PDF files using React
https://react-pdf.org
MIT License
14.77k stars 1.17k forks source link

Provide PDFDownloadLink some sort of prop that supports lazy or conditional loading? #620

Open rmolinamir opened 5 years ago

rmolinamir commented 5 years ago

Is your feature request related to a problem? Please describe. A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

Hey everyone, first off I want to say that this package is really impressive, thanks for maintaining it. Also, if going to go off on assumptions regarding this feature, so excuse me if I got anything wrong. Now on topic, I've noticed that, as expected, generating PDF files is a costly operation, performance wise. So during render, a lot of files are fetched and since my generated PDF is dynamic, the performance takes a hit due to every re-render. To optimize this behavior I currently have to do workarounds from an upper scope of the PDFDownloadLink component, for example.

Describe the solution you'd like A clear and concise description of what you want to happen.

Either delay or debounce the initial PDF generation. I think an awesome feature would be to wait X amount of seconds until the PDF should start to load, and if there is a re-render or a change in the passed props to the document prop of the PDFDownloadLink component, then simply hold it off and/or restart the timer. Basically, debounce.

Describe alternatives you've considered A clear and concise description of any alternative solutions or features you've considered.

As I mentioned earlier, either debouncing it or delaying it. I guess throttling might work fine as well but throttling doesn't seem appropriate for this use-case. Passing a shouldLoad prop would work wonders too, but it would require external logic on an upper scope.

Vpr99 commented 5 years ago

@rmolinamir I'm curious what your current workaround looks like for this. I have some dynamic things in the PDF bound to input values which (for obvious reasons) makes performance chug.

rmolinamir commented 5 years ago

Sure @Vpr99! Here's how I handled this, here are some videos of which I will explain what happens on each:

  1. Data is fetching: https://i.gyazo.com/310e000758bc20d83f10984064b6d31b.mp4
  2. Data has loaded: https://i.gyazo.com/aab52fc2b35a2e031e5a20cf88735146.mp4
  3. A showcase of the dynamic data in the PDF: https://i.gyazo.com/050e9a5f892ff30ca9f7289ebc8c5933.mp4

  1. The DOM is mounted, data is fetching, and the PDF is not going to be mounted until the data is finished loading, and a debounced handler goes uninterrupted in case the data is fetched or updated again, for whatever reason. The button that has the loading animation is basically a dummy button.
  2. Data has finished loading and after an X amount of seconds (the debounce if it goes uninterrupted) the dummy button is unmounted and in its place, I now render the PDFDownloadLink and PDFViewer components from this library with the dynamically generated document. If the debounce is interrupted then the component will fallback to its dummy button with the loading animation.
  3. Is just a showcase of the dynamic data found in the actual DOM that's also rendered in the PDF document (obviously some things had to be done to convert it and display it as shown in the DOM).

This ended up making the initial mount (shown in 1) much smoother, at first it was incredibly laggy and generating the chart would take a while if done in parallel with the PDF, both being pretty performance heavy.