From 7dae8d3fbe729ec5dfadfe2eca81562c51201ca3 Mon Sep 17 00:00:00 2001 From: NB <47492535+altmshfkgudtjr@users.noreply.github.com> Date: Sat, 15 May 2021 20:04:49 +0900 Subject: [PATCH] #3 Fix doesn't re-rerendering bug Fixed a bug where re-rendering would not work when options and styles were changed. --- public/css/index.css | 22 +-- src/index.tsx | 27 +++- src/modules/epubViewer/EpubViewer.tsx | 190 +++++++++++++----------- src/modules/epubViewer/styles.ts | 10 +- src/modules/reactViewer/ReactViewer.tsx | 37 ++--- 5 files changed, 160 insertions(+), 126 deletions(-) diff --git a/public/css/index.css b/public/css/index.css index 30cf536..881fdd4 100644 --- a/public/css/index.css +++ b/public/css/index.css @@ -1,14 +1,14 @@ -html, body { - padding: 0; - margin: 0; -} - -html { - width: 100vw; - height: 100vh; +html, +body { + padding: 0; + margin: 0; + width: 100vw; + height: 100vh; } #root { - width: 100%; - height: 100%; -} \ No newline at end of file + height: 100%; + display: flex; + align-items: center; + justify-content: center; +} diff --git a/src/index.tsx b/src/index.tsx index f785cf2..1f4dfca 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -1,20 +1,35 @@ import { useRef } from 'react' import ReactDOM from 'react-dom'; +import EpubViewer from 'modules/epubViewer/EpubViewer' import ReactEpubViewer from 'modules/reactViewer/ReactViewer' import { ViewerRef } from 'types' +interface Props { + VIEWER_TYPE?: "ReactViewer" | "EpubViewer" +} -const App = () => { +const App = ({ VIEWER_TYPE = "ReactViewer" }: Props) => { const EPUB_URL = "/react-epub-viewer/files/Alices Adventures in Wonderland.epub"; const ref = useRef(null); return ( - + <> + {VIEWER_TYPE === "ReactViewer" && <> + + + } + {VIEWER_TYPE === "EpubViewer" && <> + + + } + ); } - ReactDOM.render(, document.getElementById('root')); \ No newline at end of file diff --git a/src/modules/epubViewer/EpubViewer.tsx b/src/modules/epubViewer/EpubViewer.tsx index 83b9b83..995e2e3 100644 --- a/src/modules/epubViewer/EpubViewer.tsx +++ b/src/modules/epubViewer/EpubViewer.tsx @@ -53,84 +53,8 @@ const EpubViewer = ({ const [rendition, setRendition] = useState(null); - const [toc, setToc] = useState([]); - const currentCfi = useRef(''); - - - /** - * Init Book - * @method - * - Set book state - * - Set Epub path state - * - Set isLoaded state - * - Set toc state - */ - const initBook = () => { - if (book) { - book.destroy(); - } - - const book_ = new Book(url, epubFileOptions); - setBook(book_); - - bookChanged && bookChanged(book_); - - book_.loaded.navigation.then(({ toc }) => { - const toc_: Toc[] = toc.map(t => ({ - label: t.label, - href: t.href - })); - - setIsLoaded(true); - setToc(toc_); - tocChanged && tocChanged(toc_); - initRendition(book_); - }); - - // Init Location & Pagination - book_.ready.then(function() { - const stored = localStorage.getItem(book_.key() + '-locations'); - if (stored) { - return book_.locations.load(stored); - } else { - return book_.locations.generate(1024); - } - }).then(() => { - localStorage.setItem(book_.key() + '-locations', book_.locations.save()); - }); - }; - - /** - * Init Rendition - * @method - * - Init iframe tag on DOM element - * - Set rendition - * - Set start page - */ - const initRendition = (book_: Book) => { - const node = ref.current; - if (!node || !book_) return; - - const rendition_ = book_.renderTo(node, { - width: "100%", - height: "100%", - ...epubOptions - }); - setRendition(rendition_); - - rendtionChanged && rendtionChanged(rendition_); - - if(typeof location === "string") { - rendition_.display(location); - } else if(toc.length > 0 && toc[0].href) { - rendition_.display(toc[0].href); - } else { - rendition_.display(); - } - } - /** * Move page * @method @@ -238,20 +162,114 @@ const EpubViewer = ({ - /** Ref checker */ + /** Ref Checker */ useEffect(() => { if (!ref) { throw new Error("[React-Epub-Viewer] Put a ref argument that has a ViewerRef type."); } }, [ref]); - /** Epub Init */ - /* eslint-disable */ + /** Epub init options Changed */ useEffect(() => { if (!url) return; - initBook(); - }, [url]); - /* eslint-enable */ + + let mounted: boolean = true; + let book_: Book | any = null; + + if (!mounted) return; + + if (book_) { + book_.destroy(); + } + + book_ = new Book(url, epubFileOptions); + setBook(book_); + + return () => { + mounted = false; + } + }, [url, epubFileOptions, setBook, setIsLoaded]); + + /** Book Changed */ + useEffect(() => { + if (!book) return; + + if (bookChanged) bookChanged(book); + + book.loaded.navigation.then(({ toc }) => { + const toc_: Toc[] = toc.map(t => ({ + label: t.label, + href: t.href + })); + + setIsLoaded(true); + if (tocChanged) tocChanged(toc_); + }); + + book.ready.then(function() { + if (!book) return; + + const stored = localStorage.getItem(book.key() + '-locations'); + if (stored) { + return book.locations.load(stored); + } else { + return book.locations.generate(1024); + } + }).then(() => { + if (!book) return; + localStorage.setItem(book.key() + '-locations', book.locations.save()); + }); + }, [book, bookChanged, tocChanged]); + + /** Rendition Changed */ + useEffect(() => { + if (!rendition) return; + + if (rendtionChanged) rendtionChanged(rendition); + }, [rendition, rendtionChanged]); + + /** Viewer Option Changed */ + useEffect(() => { + let mounted = true; + if (!book) return; + + const node = ref.current; + if (!node) return; + node.innerHTML = ""; + + book.ready.then(function() { + if (!mounted) return; + + if (book.spine) { + const loc = book.rendition?.location?.start?.cfi; + + // if (book.rendition) book.rendition.destroy(); + + const rendition_ = book.renderTo(node, { + width: "100%", + height: "100%", + ...epubOptions + }); + setRendition(rendition_); + + if(loc) { + rendition_.display(loc) + } else { + rendition_.display(); + } + } + }); + + return () => { + mounted = false; + } + }, [ref, book, epubOptions, style, setRendition]); + + /** Location Changed */ + useEffect(() => { + if (!ref.current || !location) return; + if (ref.current.setLocation) ref.current.setLocation(location); + }, [ref, location]); /** * Emit Viewer Event @@ -284,14 +302,6 @@ const EpubViewer = ({ ]); /* eslint-enable */ - /** Display page by changed location */ - useEffect(() => { - if (!location || !rendition) return; - - rendition.display(location); - }, [location, rendition]); - - return (<> {!isLoaded && loadingView}
diff --git a/src/modules/epubViewer/styles.ts b/src/modules/epubViewer/styles.ts index 815fb0d..c9cc56d 100644 --- a/src/modules/epubViewer/styles.ts +++ b/src/modules/epubViewer/styles.ts @@ -3,10 +3,16 @@ */ const styles: { boxSizing: any, - margin: any + margin: any, + width: any, + height: any, + overflowY: any } = { boxSizing: "border-box", - margin: "0px auto" + margin: "0px auto", + width: "100%", + height: "100%", + overflowY: 'hidden' } export default styles \ No newline at end of file diff --git a/src/modules/reactViewer/ReactViewer.tsx b/src/modules/reactViewer/ReactViewer.tsx index 23f74a6..5442d1c 100644 --- a/src/modules/reactViewer/ReactViewer.tsx +++ b/src/modules/reactViewer/ReactViewer.tsx @@ -50,14 +50,14 @@ const ReactViewer = ({ const [rendition, setRendition] = useState(null); - const [layoutStyle, setLayoutStyle] = useState({}); + const [layoutStyle, setLayoutStyle] = useState<{[key: string]: any}>({}); const [bookStyle, setBookStyle] = useState({ fontFamily: 'Origin', - fontSize: 18, + fontSize: 16, lineHeight: 1.4, - marginHorizontal: 15, - marginVertical: 5 + marginHorizontal: 0, + marginVertical: 0 }); const [bookOption, setBookOption] = useState({ @@ -71,8 +71,6 @@ const ReactViewer = ({ contents: null }); - - /** * Run book changed * @method @@ -118,17 +116,23 @@ const ReactViewer = ({ const h = bookOption.flow === "scrolled-doc" ? win_h - componentHeight : win_h - componentHeight - ~~((win_h - componentHeight - viewerLayout_.MIN_VIEWER_HEIGHT) / 100 * bookStyle.marginVertical); - const marginTop = bookOption.flow === "scrolled-doc" + const marginVertical = bookOption.flow === "scrolled-doc" ? "" : `${~~((win_h - componentHeight - viewerLayout_.MIN_VIEWER_HEIGHT) / 100 * bookStyle.marginVertical) / 2}px`; - setLayoutStyle(l => ({ - ...l, - width: w, - height: h, - marginTop - })); - + setLayoutStyle(layout => { + if (layout.width !== w || layout.height !== h || layout.marginTop !== marginVertical) { + return { + ...layout, + width: w, + height: h, + marginTop: marginVertical, + marginBottom: marginVertical + }; + } + return layout; + }); + try { rendition.resize(w, h); } catch { } @@ -212,8 +216,8 @@ const ReactViewer = ({ /** Set viewer Styles/Options */ useEffect(() => { - viewerStyle && setBookStyle(viewerStyle); - viewerOption && setBookOption(viewerOption); + viewerStyle && setBookStyle(v => ({ ...v, ...viewerStyle })); + viewerOption && setBookOption(v => ({ ...v, ...viewerOption })); }, [viewerStyle, viewerOption]); /** Apply viewer Styles/Options */ @@ -277,7 +281,6 @@ const ReactViewer = ({ rendition.on("mouseup", onSelected); return () => rendition.off("mouseup", onSelected); }, [rendition, onSelected]); - return (<>