React-pdf: Blank pages and duplicate content in Firefox

Created on 5 Feb 2019  Â·  18Comments  Â·  Source: diegomura/react-pdf

Describe the bug
Some content (typically the first or last content on a page) is:

  • duplicated on the next page (and, in <=v1.2.2, also beside the original content, offset horizontally)
  • offset by one or more pages, resulting in extra blank pages being inserted

_The improvement between 1.2.2 and 1.2.3 is probably caused by #469; thank you @arahansen! — do you have any ideas about the remaining layout bug by any chance?_

To Reproduce
This is hard to reproduce — the code sample we developed for the REPL doesn’t exhibit the error unfortunately

Expected behavior
No unexpected duplicate content, offsets or blank pages

Screenshots
Note the content offset horizontally in the last page visible on Firefox with [email protected].

| Firefox + [email protected] | Firefox + [email protected] | Chrome + [email protected] |
|-|-|-|
| react-pdf 1 2 2 firefox | react-pdf 1 2 3 firefox | react-pdf 1 2 3 chrome |

Desktop (please complete the following information):

  • OS: MacOS
  • Browser: Firefox 64, Chrome 71
  • React-pdf version: 1.2.2 and 1.2.3
bug

Most helpful comment

I think i found the solution, i oppened a issue about blank pages, but in the same day i found a way to
work around this issue. So what i did was a conditional render to my pdf, to not render with all page.

This way the generator give me error

 <PDFDownloadLink document={<RelFatura dados={this.state.excel} titulo={'Voucher a faturar'} />} fileName="Vouchers.pdf">
    {({ blob, url, loading, error }) => (loading ? <i className="fa fa-file-pdf-o"> Loading document...</i> : <i className="fa fa-file-pdf-o"> Gerar pdf </i>)}
 </PDFDownloadLink>                

what i did was this:

{this.state.pdf &&<div>
    <PDFDownloadLink document={<RelFatura dados={this.state.excel} titulo={'Voucher a faturar'} />} fileName="Vouchers.pdf">
        ({ blob, url, loading, error }) => (loading ? <i className="fa fa-file-pdf-o"> Loading document...</i> : <i className="fa fa-file-pdf-o"> Gerar pdf </i>)}
    </PDFDownloadLink>
</div>}

So you put a button like "exports" and when you press you can trigger a setState that put true on pdf and show your pdf generator. This is the only way I found to generate without the error

All 18 comments

Thinking this through... since the improvement between 1.2.2 and 1.2.3 can only be caused by #469, which literally _only changes the horizontal offset of text_..... logically we must have been rendering at least two copies of the text and _we are still rendering two copies_, only now they are on top of each other.

And... in addition... we are also rendering at least a third copy of some of the text, which fits with @naminho’s hypothesis in #420 that multiple renders are writing to the same stream, doesn’t it?

Interesting..
First, thanks for reporting this. This is critical.

I never saw a scenario in which some text get's rendered twice in the doc, but apparently this is happening, and yes, maybe now you just have two copies of the same text one on top of the other. In order to generate those screenshots, your project ran more than one render?

The REPL example you shared it's not working. I guess it's because the url is too long? I thought I was checking this on the REPL code but apparently if fails.

Implementing a queue solution on how documents render (as @naminho suggested) would be the first step I would do, just to be sure this is not happening because of multiple render calls on the same document instance. Besides, it's necessary. I'll try to tackle that asap and after that we can see if this issue remains. Sounds good?

Thank you, this sounds great 👍 and I’ll look more into the multiple renders in our codebase tomorrow. We are not _intentionally_ rendering multiple times! But we are wrapping the document in a Redux provider, which might have something to do with it. Yes, the REPL URL is probably too long to display. Anyway, it’s probably not that interesting really since it doesn’t appear to reproduce the bug.

I can confirm we are not calling the PDF document’s container’s render method more than once:

Error: WebGL warning: getContext: Disallowing antialiased backbuffers due to blacklisting. mbox-contents-eb84853a4f17846647494ffe63c8207c1860a736-staging.js:18:13909
Rendering PDF app! App.pdf.js:23
Successfully compiled asm.js code (loaded from cache in 5ms) clientPdf.js
Error: stream.push() after EOF (_stream_readable.js:271)
Warning: Indexing all PDF objects pdf.worker.js:1168:5
PDF 72d4d57e593ce5b94426fd76d93e9a5b [1.3 react-pdf / react-pdf] (PDF.js: 2.1.97) viewer.js:1179:7
Warning: Invalid absolute docBaseUrl: "blob:http://localhost/6f48285f-9fc9-ea49-ad01-6ca142ed2ff8".

I am still puzzled about why this is only happening in Firefox and IE... as well as the #420 bug I’m wondering if there might also be a bug in Firefox’s PDF viewer.

Indeed. That’s very weird đŸ€”
I want to work on this. Do you have any snippet for me to replicate this? That would be incredibly helpful 😊

Sure. I’ve sent you an email with a snippet that shows how our code is structured, let me know if you need any more detail!

@diegomura We have noticed that sometimes this duplicate offset text is also occurring for some users in Chrome (noticed in Chrome 72.0.3626.109) 😞 so it’s now potentially user-facing and we need to make this a high priority for our team. If you have any pointers as to where those duplicate renders might be occurring or how to squash them it would be really helpful. Thank you!

Agreed. This is critical, and I still think it’s related to #420.

I think the cause of this is that the element tree is shared between render calls, and it changes acordongly to changes in the JSX tree by calling ‘renderer.updateContainer’. This is a sync process, but rendering is async. This causes some race conditions when successive updates happen very quickly. This may also be the cause why some elements are rendered in the previous PDF document instance, causing blank pages and duplicate texts. Does this make sense?

Anyway, I think we need to have a way to delay a container update until rendering finishes, and not triggering any new render if there is one currently running. I have no clue yet how to do this. We might need to change the ‘pdf’ function API

I think i found the solution, i oppened a issue about blank pages, but in the same day i found a way to
work around this issue. So what i did was a conditional render to my pdf, to not render with all page.

This way the generator give me error

 <PDFDownloadLink document={<RelFatura dados={this.state.excel} titulo={'Voucher a faturar'} />} fileName="Vouchers.pdf">
    {({ blob, url, loading, error }) => (loading ? <i className="fa fa-file-pdf-o"> Loading document...</i> : <i className="fa fa-file-pdf-o"> Gerar pdf </i>)}
 </PDFDownloadLink>                

what i did was this:

{this.state.pdf &&<div>
    <PDFDownloadLink document={<RelFatura dados={this.state.excel} titulo={'Voucher a faturar'} />} fileName="Vouchers.pdf">
        ({ blob, url, loading, error }) => (loading ? <i className="fa fa-file-pdf-o"> Loading document...</i> : <i className="fa fa-file-pdf-o"> Gerar pdf </i>)}
    </PDFDownloadLink>
</div>}

So you put a button like "exports" and when you press you can trigger a setState that put true on pdf and show your pdf generator. This is the only way I found to generate without the error

Yes, the main problem it's re-render of component.

Hi! Sorry for not having any updates on this yet. It's been some crazy days of work. But I'll come back soon to tackle this and all other issues 😄

I ran into this issue as well by the way. In my case, the error prop/parameter was set as true when this happened. So basically every time I had error being true I forced a re-render to make the PDF generate over and over until error was false. Hacky, but worked.

To force the re-renders I simply started changing the key props that you might pass to a component. Every time the key changes, a new instance is mounted and the old one is unmounted.

Any update on this? Thanks.

P.S. Otherwise a great package!

I ran into this issue as well by the way. In my case, the error prop/parameter was set as true when this happened. So basically every time I had error being true I forced a re-render to make the PDF generate over and over until error was false. Hacky, but worked.

To force the re-renders I simply started changing the key props that you might pass to a component. Every time the key changes, a new instance is mounted and the old one is unmounted.

It worked for me, thanks!

Hi! Any updates on this bug?

I ran into this issue as well by the way. In my case, the error prop/parameter was set as true when this happened. So basically every time I had error being true I forced a re-render to make the PDF generate over and over until error was false. Hacky, but worked.

To force the re-renders I simply started changing the key props that you might pass to a component. Every time the key changes, a new instance is mounted and the old one is unmounted.

worked for me as well.. thanks for the solution. I was going crazy with this bug

@Deepaliyadav @fr4nkydevelop3r Could you please shed some light as to how specifically you implemented this fix? The element being included once is indeed an array element (rendered with a .map()) but changing the key does not seem to resolve the issue in my case.

@Deepaliyadav @fr4nkydevelop3r Could you please shed some light as to how specifically you implemented this fix? The element being included once is indeed an array element (rendered with a .map()) but changing the key does not seem to resolve the issue in my case.

@ihd-dev the blank pages we were getting was because f re-rendering of page and this hack prevent unnecessary re-rendering..

`function Pdf() {
const [ temp, setTemp] = useState(Math.random());

useEffect(() => { 
    setTemp(Math.random());
}, []);
return (
        <ApplicationPdf  />
                </PDFViewer>
);

}

export default Pdf;`

Here's how I implemented this in my code. I hope it helps :)

Was this page helpful?
1 / 5 - 1 ratings

Related issues

brandly picture brandly  Â·  3Comments

pavle-lekic-htec picture pavle-lekic-htec  Â·  4Comments

cheald picture cheald  Â·  3Comments

benbenedek picture benbenedek  Â·  3Comments

UsefulHunter picture UsefulHunter  Â·  3Comments