From 9219bfdfebea40c28907886e0304bd7c307a04c9 Mon Sep 17 00:00:00 2001 From: "konstantin.knuetel" Date: Thu, 26 Aug 2021 22:03:49 +0200 Subject: [PATCH 1/5] add test for Page outside Document --- test/LoadingOptions.jsx | 16 ++++++ test/Test.jsx | 106 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 121 insertions(+), 1 deletion(-) 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..0a0a43876 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); @@ -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, +}; From e1d75852acdb2183634d1037210e73b3a04dc62b Mon Sep 17 00:00:00 2001 From: "konstantin.knuetel" Date: Thu, 26 Aug 2021 22:10:12 +0200 Subject: [PATCH 2/5] cancel load if destroyed Don't call pdf.getPage() if Document is destroyed --- src/Page.jsx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/Page.jsx b/src/Page.jsx index 371655b72..47d24e59b 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('Attempted to load a page, but the document was destroyed'); + return; + } + const cancellable = makeCancellable(pdf.getPage(pageNumber)); this.runningTask = cancellable; From 5bf5a11227b72cdc6e2c09b6bdb9f960179a72ca Mon Sep 17 00:00:00 2001 From: "konstantin.knuetel" Date: Thu, 26 Aug 2021 22:43:30 +0200 Subject: [PATCH 3/5] abort file load on document reload/unmount --- src/Document.jsx | 16 ++++++++++++++-- src/shared/utils.js | 12 +++++++++--- test/Test.jsx | 2 +- 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/src/Document.jsx b/src/Document.jsx index 7b78da7e5..265c5a23f 100644 --- a/src/Document.jsx +++ b/src/Document.jsx @@ -85,8 +85,13 @@ 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.abort(); + } } loadDocument = () => { @@ -263,7 +268,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.abort(); + } + + this.loadFromFileTask = loadFromFile(file); + this.loadFromFileTask.promise.then((data) => { + this.loadFromFileTask = null; resolve({ data }); }); return; diff --git a/src/shared/utils.js b/src/shared/utils.js index e6e38fd4f..5cc643fa7 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, + abort: () => { + reader.abort(); + }, + }; } diff --git a/test/Test.jsx b/test/Test.jsx index 0a0a43876..6ca992c15 100644 --- a/test/Test.jsx +++ b/test/Test.jsx @@ -149,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; From c091eba09adb1eeddc7188d2a8cbd8caeb7dd054 Mon Sep 17 00:00:00 2001 From: "konstantin.knuetel" Date: Fri, 17 Sep 2021 15:56:44 +0200 Subject: [PATCH 4/5] change according to comments - call onLoadError() with Error() - inline if() for code consistency --- src/Document.jsx | 4 +--- src/Page.jsx | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Document.jsx b/src/Document.jsx index 265c5a23f..3b63fd5e4 100644 --- a/src/Document.jsx +++ b/src/Document.jsx @@ -89,9 +89,7 @@ export default class Document extends PureComponent { if (this.loadingTask) this.loadingTask.destroy(); // If FileReader loading is in progress, let's abort it - if (this.loadFromFileTask) { - this.loadFromFileTask.abort(); - } + if (this.loadFromFileTask) this.loadFromFileTask.abort(); } loadDocument = () => { diff --git a/src/Page.jsx b/src/Page.jsx index 47d24e59b..40d53480b 100644 --- a/src/Page.jsx +++ b/src/Page.jsx @@ -249,7 +249,7 @@ export class PageInternal extends PureComponent { // eslint-disable-next-line no-underscore-dangle if (pdf && pdf._transport && pdf._transport.destroyed) { this.setState({ page: false }); - this.onLoadError('Attempted to load a page, but the document was destroyed'); + this.onLoadError(new Error('Attempted to load a page, but the document was destroyed')); return; } From f556d78cff2f7f557aec43bdc262f14b54eee2e2 Mon Sep 17 00:00:00 2001 From: "konstantin.knuetel" Date: Fri, 17 Sep 2021 15:59:35 +0200 Subject: [PATCH 5/5] rename .abort() to .cancel() --- src/Document.jsx | 4 ++-- src/shared/utils.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Document.jsx b/src/Document.jsx index 3b63fd5e4..59a0b1f07 100644 --- a/src/Document.jsx +++ b/src/Document.jsx @@ -89,7 +89,7 @@ export default class Document extends PureComponent { if (this.loadingTask) this.loadingTask.destroy(); // If FileReader loading is in progress, let's abort it - if (this.loadFromFileTask) this.loadFromFileTask.abort(); + if (this.loadFromFileTask) this.loadFromFileTask.cancel(); } loadDocument = () => { @@ -268,7 +268,7 @@ export default class Document extends PureComponent { if (isBlob(file) || isFile(file)) { // abort previous FileReader, if there is one if (this.loadFromFileTask) { - this.loadFromFileTask.abort(); + this.loadFromFileTask.cancel(); } this.loadFromFileTask = loadFromFile(file); diff --git a/src/shared/utils.js b/src/shared/utils.js index 5cc643fa7..9c4403cb6 100644 --- a/src/shared/utils.js +++ b/src/shared/utils.js @@ -165,7 +165,7 @@ export function loadFromFile(file) { return { promise, - abort: () => { + cancel: () => { reader.abort(); }, };