react-pdf
react-pdf copied to clipboard
Caching loaded documents for reuse
Before you start - checklist
- [x] I have read documentation in README
- [x] I have checked sample and test suites to see real life basic implementation
- [x] I have checked if this question is not already asked
What are you trying to achieve? Please describe.
I have an application that can render multiple PDF documents. The user can select a document from the menu. Currently, whenever the user selects a document, the PDF file is always fetched anew from the server, even if it was already viewed prior. This puts a load on the network, as some documents can reach several MBs in size. I'm looking for a way to cache those PDF documents (incl. all pages) to avoid repeated requests (esp. on metered networks).
Describe solutions you've tried
I tried a naive approach to hook into onLoadSuccess
and save the PdfDocumentProxy
object into state
state = { pdfs: {} }
onDocumentLoadSuccess = pdf => {
const selectedId = 'xyz'
this.setState(({ pdfs }) => ({
...pdfs,
[selectedId]: pdf
}))
}
and then pass the saved object via file
prop
render () {
const { pdfs } = this.state
const selectedUrl = 'https://example.com/example.pdf', selectedId = 'xyz'
// If cached, use it, else fetch fresh from the API
const pdf = pdfs[selectedId] ? pdfs[selectedId] : selectedUrl
return <Document file={pdf} ... />
}
However, this doesn't work as file
prop doesn't interpret PdfDocumentProxy
objects. I also looked into other hooks such as onSourceSuccess
, but it's not clear how I could retrieve the contents of the PDF file with either one.
Question
Is there any recommendations for caching PDFs with react-pdf
? I looked into this in pdfjs-dist
but didn't find anything conclusive. Any suggestions as far which store would be appropriate? I know of limitations of localStorage (5MB), IndexedDB (50MB/5MB), perhaps a POJO map could work? Or is this a silly idea altogether?
Environment
-
react-pdf
:4.0.2
-
react
:16.7.0
-
node
:10
- Browser: IE11, Chrome, FF, Safari
onLoadSuccess
returns an object which represents a loaded document. You can't pass it back to file prop.
You can use fetch()
to download the PDFs you need, and use FileReader
on fetch()
result to get a File
or Blob
object with a binary representation of the file, which you can later pass to file
prop, which will be re-opened by React-PDF without downloading it again.
@wojtekmaj There is a way to render the whole document/prefetch and cache all pages so we can have the blob cached and can be quickly redrawn?
Instead of calling pdf.getPage() on the next set of page numbers, which would fetch the data (I am not certain if it will create the image blob).
@igoroctaviano I'd ask Mozilla on their pdf.js project site, but the solution could be also to simply handle downloading the file by yourself, and passing a Blob instead of an URL to React-PDF.
@wojtekmaj Is there an example of this anywhere? I'm trying to implement the file download myself, and I'm creating a new Blob, however, react-pdf doesn't render anything. I'm not sure what I'm doing wrong..
@wojtekmaj Can you share an example of fetching file data then passing the data to the component?
@daweimau,
const [PDFBlob, setPDFBlob] = useState(null)
useEffect(() => {
const controller = new AbortController();
fetch(url, { signal: controller.signal })
.then(res => res.blob())
.then(file => setPDFBlob(file))
.catch(e => {
if(e.name !== 'AbortError') { /* handle error*/ }
});
return () => controller.abort();
}, [url, setPDFBlob]);
return PDFBlob && <Document file={PDFBlob} ...
@daweimau,
const [PDFBlob, setPDFBlob] = useState(null) useEffect(() => { const controller = new AbortController(); fetch(url, { signal: controller.signal }) .then(res => res.blob()) .then(file => setPDFBlob(file)) .catch(e => { if(e.name !== 'AbortError') { /* handle error*/ } }); return () => controller.abort(); }, [url, setPDFBlob]); return PDFBlob && <Document file={PDFBlob} ...
That worked thanks!
This issue is stale because it has been open 90 days with no activity. Remove stale label or comment or this issue will be closed in 14 days.
This issue was closed because it has been stalled for 14 days with no activity.