diff --git a/src/Document.jsx b/src/Document.jsx index 7b78da7e5..59a0b1f07 100644 --- a/src/Document.jsx +++ b/src/Document.jsx @@ -85,8 +85,11 @@ export default class Document extends PureComponent { // If rendering is in progress, let's cancel it cancelRunningTask(this.runningTask); - // If loading is in progress, let's destroy it + // If pdfjs loading is in progress, let's destroy it if (this.loadingTask) this.loadingTask.destroy(); + + // If FileReader loading is in progress, let's abort it + if (this.loadFromFileTask) this.loadFromFileTask.cancel(); } loadDocument = () => { @@ -263,7 +266,14 @@ export default class Document extends PureComponent { if (isBrowser) { // File is a Blob if (isBlob(file) || isFile(file)) { - loadFromFile(file).then((data) => { + // abort previous FileReader, if there is one + if (this.loadFromFileTask) { + this.loadFromFileTask.cancel(); + } + + this.loadFromFileTask = loadFromFile(file); + this.loadFromFileTask.promise.then((data) => { + this.loadFromFileTask = null; resolve({ data }); }); return; diff --git a/src/Page.jsx b/src/Page.jsx index 371655b72..40d53480b 100644 --- a/src/Page.jsx +++ b/src/Page.jsx @@ -246,6 +246,13 @@ export class PageInternal extends PureComponent { return { page: null }; }); + // eslint-disable-next-line no-underscore-dangle + if (pdf && pdf._transport && pdf._transport.destroyed) { + this.setState({ page: false }); + this.onLoadError(new Error('Attempted to load a page, but the document was destroyed')); + return; + } + const cancellable = makeCancellable(pdf.getPage(pageNumber)); this.runningTask = cancellable; diff --git a/src/shared/utils.js b/src/shared/utils.js index e6e38fd4f..9c4403cb6 100644 --- a/src/shared/utils.js +++ b/src/shared/utils.js @@ -141,9 +141,8 @@ export function isCancelException(error) { } export function loadFromFile(file) { - return new Promise((resolve, reject) => { - const reader = new FileReader(); - + const reader = new FileReader(); + const promise = new Promise((resolve, reject) => { reader.onload = () => resolve(new Uint8Array(reader.result)); reader.onerror = (event) => { switch (event.target.error.code) { @@ -163,4 +162,11 @@ export function loadFromFile(file) { return null; }); + + return { + promise, + cancel: () => { + reader.abort(); + }, + }; } diff --git a/test/LoadingOptions.jsx b/test/LoadingOptions.jsx index d77ae240c..ba37e58ff 100644 --- a/test/LoadingOptions.jsx +++ b/test/LoadingOptions.jsx @@ -8,6 +8,8 @@ import { isFile } from './shared/propTypes'; export default function LoadingOptions({ file, setFile, + useExternPage, + setUseExternPage, setRender, }) { function onFileChange(event) { @@ -122,6 +124,18 @@ export default function LoadingOptions({ Unload file + +
+ { setUseExternPage(event.target.checked); }} + /> + +
); } @@ -130,4 +144,6 @@ LoadingOptions.propTypes = { file: isFile, setFile: PropTypes.func.isRequired, setRender: PropTypes.func.isRequired, + setUseExternPage: PropTypes.func.isRequired, + useExternPage: PropTypes.bool.isRequired, }; diff --git a/test/Test.jsx b/test/Test.jsx index ccdfb7dee..6ca992c15 100644 --- a/test/Test.jsx +++ b/test/Test.jsx @@ -12,6 +12,8 @@ import { loadFromFile, } from 'react-pdf/src/shared/utils'; +import { isFile as propTypeIsFile } from './shared/propTypes'; + import './Test.less'; import AnnotationOptions from './AnnotationOptions'; @@ -54,6 +56,7 @@ export const readAsDataURL = (file) => new Promise((resolve, reject) => { export default function Test() { const [displayAll, setDisplayAll] = useState(false); + const [useExternPage, setUseExternPage] = useState(false); const [externalLinkTarget, setExternalLinkTarget] = useState(null); const [file, setFile] = useState(null); const [fileForProps, setFileForProps] = useState(null); @@ -146,7 +149,7 @@ export default function Test() { if (isBrowser) { // File is a Blob if (isBlob(file) || isFile(file)) { - return { data: await loadFromFile(file) }; + return { data: await loadFromFile(file).promise }; } } return file; @@ -219,6 +222,8 @@ export default function Test() {
- console.log('Clicked a document', { event, pdf })} @@ -319,9 +325,107 @@ export default function Test() { )} + {/* eslint-disable-next-line */} + // eslint-disable-next-line indent + : }
); } + +// test element outside of element +const TestSeparateDocumentAndPage = function (props) { + const { file } = props; + const [display, setDisplay] = useState(true); + const [displayPage, setDisplayPage] = useState(true); + const [document, setDocument] = useState(null); + const [numPages, setNumPages] = useState(0); + const [pageNumber, setPageNumber] = useState(1); + const [unountOnFile, setUnountOnFile] = useState(false); + + // unmount Document as soon as file starts loading + useEffect(() => { + if (file && unountOnFile) { + setDisplay(false); + } + }, [file]); + + const onDocumentLoadSuccess = (pdf) => { + console.log('Loaded a document', pdf); + if (pdf && pdf.numPages) { + setNumPages(pdf.numPages); + } + setDocument(pdf); + }; + + const onPageLoadSuccess = (page) => { + console.log('Loaded a page', page); + }; + + const onPageLoadError = (error) => { + console.log('error loading a page:', error); + }; + + const toggleDocument = () => { + setDisplay(!display); + }; + + const pageNumberDec = () => { + if (pageNumber > 1) { + setPageNumber(pageNumber - 1); + } + }; + + const pageNumberInc = () => { + if (pageNumber < numPages) { + setPageNumber(pageNumber + 1); + } + }; + + const togglePage = () => { + setDisplayPage(!displayPage); + }; + + return ( +
+ + + + + { setUnountOnFile(event.target.checked); }} + /> + + + + Page: + { pageNumber } + + +
+ { !display ? null : } + { !displayPage || !document + ? null + : ( + + ) } +
+
+ ); +}; + +TestSeparateDocumentAndPage.propTypes = { + file: propTypeIsFile, +};