MatthewHerbst / react-to-print

Print React components in the browser. Supports Chrome, Safari, Firefox and EDGE
MIT License
2.06k stars 221 forks source link

Unhandled error when trying to print not fully loaded canvas elements #707

Closed brycenaddison closed 3 weeks ago

brycenaddison commented 3 months ago

Hi, I have an app and I'm trying to use react-to-print to print some graphs on canvas elements. However, when a print is called before these graphs have fully rendered in, I can consistently get this error:

image

I have no problem with the print not working, however, this error never sees the onPrintError function and it doesn't look like there's any way to externally have this error handled. The onAfterPrint callback is never called either, so there's also no way to know that the error has happened other than checking the console. Preferably, there would be a way to have this error be handled gracefully.

MatthewHerbst commented 3 months ago

Hey, thanks for reporting in! Since the error is "uncaught" that indicates nothing is handling/catching it, which is definitely not great! We have a canvas as part of our examples and that seems to work, but it's very possible we need to do more to ensure everything has loaded.

Would it be possible for you to share a reproducible example on Codesandbox or some other tool so that I can debug this properly?

brycenaddison commented 3 months ago

@MatthewHerbst Looks like it has something to do with delayed/asynchronous loading of canvases: https://codesandbox.io/p/sandbox/react-to-print-uncaught-error-83fksn

MatthewHerbst commented 3 months ago

Thanks for the link! Will look to get a fix in this weekend!

MatthewHerbst commented 3 weeks ago

Finally got a chance to play with this more. Seems that you resolve the onBeforeGetContent promise before the setState in LineChart completes. You're also not waiting for the setLoadCharts call to complete. Regardless, the reason this crashes with canvas elements in particular is that we have to do some special handling of canvas elements. Unlike all other elements, instead of loading the canvas elements from our internal clone of the content, we instead read them directly off the content. This is because cloneNode doesn't properly copy canvas elements which is explicitly called out.

Anyways, you can easily solve this in your code by properly waiting for the setLoadCharts call and ensuring the LineChart state effects have actually happened (or, just remove the useEffect+useState and render them directly...)

I will be adding a check in with a log message that will ensure we don't hard crash here, and will hopefully help folks determine the issue faster.

Thanks again for reporting this, very interesting and got me into the weeds on some core HTML functions (cloneNode vs importNode)

MatthewHerbst commented 3 weeks ago

Here is a forked version of your sandbox showing how to do it: https://codesandbox.io/p/sandbox/react-to-print-uncaught-error-forked-7l7rpk?file=%2Fsrc%2FApp.tsx%3A11%2C11