Prevent TypeError and incorrect state updates for "pageLoadStates"
Page load state updates of an already closed chapter caused TypeErrors or incorrect state updates.
This commit is contained in:
@@ -104,7 +104,10 @@ const BaseReaderNavBarDesktopActions = memo(
|
|||||||
<IconButton
|
<IconButton
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setPageLoadStates((statePageLoadStates) =>
|
setPageLoadStates((statePageLoadStates) =>
|
||||||
statePageLoadStates.map((pageLoadState) => ({ loaded: pageLoadState.loaded })),
|
statePageLoadStates.map((pageLoadState) => ({
|
||||||
|
url: pageLoadState.url,
|
||||||
|
loaded: pageLoadState.loaded,
|
||||||
|
})),
|
||||||
);
|
);
|
||||||
setRetryFailedPagesKeyPrefix(`${pageRetryKeyPrefix.current}`);
|
setRetryFailedPagesKeyPrefix(`${pageRetryKeyPrefix.current}`);
|
||||||
pageRetryKeyPrefix.current = (pageRetryKeyPrefix.current + 1) % 1000;
|
pageRetryKeyPrefix.current = (pageRetryKeyPrefix.current + 1) % 1000;
|
||||||
|
|||||||
@@ -88,10 +88,15 @@ const BaseReaderPage = ({
|
|||||||
onError: ReaderPagerProps['onError'];
|
onError: ReaderPagerProps['onError'];
|
||||||
setRef?: (pagesIndex: number, ref: HTMLElement | null) => void;
|
setRef?: (pagesIndex: number, ref: HTMLElement | null) => void;
|
||||||
}) => {
|
}) => {
|
||||||
|
const { src } = props;
|
||||||
|
|
||||||
const isTabletWidth = MediaQuery.useIsTabletWidth();
|
const isTabletWidth = MediaQuery.useIsTabletWidth();
|
||||||
|
|
||||||
const handleLoad = useCallback(() => onLoad?.(pagesIndex, isPrimaryPage), [onLoad, pagesIndex, isPrimaryPage]);
|
const handleLoad = useCallback(
|
||||||
const handleError = useCallback(() => onError?.(pageIndex), [onError, pageIndex]);
|
() => onLoad?.(pagesIndex, src, isPrimaryPage),
|
||||||
|
[onLoad, pagesIndex, src, isPrimaryPage],
|
||||||
|
);
|
||||||
|
const handleError = useCallback(() => onError?.(pageIndex, src), [onError, pageIndex, src]);
|
||||||
const updateRef = useCallback((element: HTMLElement | null) => setRef?.(pagesIndex, element), [pagesIndex, setRef]);
|
const updateRef = useCallback((element: HTMLElement | null) => setRef?.(pagesIndex, element), [pagesIndex, setRef]);
|
||||||
|
|
||||||
if (!display && !shouldLoad) {
|
if (!display && !shouldLoad) {
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ import {
|
|||||||
TReaderScrollbarContext,
|
TReaderScrollbarContext,
|
||||||
} from '@/modules/reader/types/Reader.types.ts';
|
} from '@/modules/reader/types/Reader.types.ts';
|
||||||
import { userReaderStatePagesContext } from '@/modules/reader/contexts/state/ReaderStatePagesContext.tsx';
|
import { userReaderStatePagesContext } from '@/modules/reader/contexts/state/ReaderStatePagesContext.tsx';
|
||||||
import { getDoublePageModePages } from '@/modules/reader/utils/ReaderPager.utils.tsx';
|
import { getDoublePageModePages, isPageOfOutdatedPageLoadStates } from '@/modules/reader/utils/ReaderPager.utils.tsx';
|
||||||
import { useReaderScrollbarContext } from '@/modules/reader/contexts/ReaderScrollbarContext.tsx';
|
import { useReaderScrollbarContext } from '@/modules/reader/contexts/ReaderScrollbarContext.tsx';
|
||||||
import { MediaQuery } from '@/modules/core/utils/MediaQuery.tsx';
|
import { MediaQuery } from '@/modules/core/utils/MediaQuery.tsx';
|
||||||
import { ReaderControls } from '@/modules/reader/services/ReaderControls.ts';
|
import { ReaderControls } from '@/modules/reader/services/ReaderControls.ts';
|
||||||
@@ -171,10 +171,20 @@ const BaseReaderViewer = forwardRef(
|
|||||||
[actualPages, readingMode],
|
[actualPages, readingMode],
|
||||||
);
|
);
|
||||||
|
|
||||||
const onError = useCallback((pageIndex: number) => {
|
const onError = useCallback((pageIndex: number, url: string) => {
|
||||||
setPageLoadStates((statePageLoadStates) =>
|
setPageLoadStates((statePageLoadStates) => {
|
||||||
statePageLoadStates.toSpliced(pageIndex, 1, { loaded: false, error: true }),
|
const pageLoadState = statePageLoadStates[pageIndex];
|
||||||
);
|
|
||||||
|
if (isPageOfOutdatedPageLoadStates(url, pageLoadState)) {
|
||||||
|
return statePageLoadStates;
|
||||||
|
}
|
||||||
|
|
||||||
|
return statePageLoadStates.toSpliced(pageIndex, 1, {
|
||||||
|
...pageLoadState,
|
||||||
|
loaded: false,
|
||||||
|
error: true,
|
||||||
|
});
|
||||||
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
// reset spread state
|
// reset spread state
|
||||||
|
|||||||
@@ -17,7 +17,9 @@ export const ReaderStatePagesContextProvider = ({ children }: { children: ReactN
|
|||||||
const [currentPageIndex, setCurrentPageIndex] = useState<ReaderStatePages['currentPageIndex']>(0);
|
const [currentPageIndex, setCurrentPageIndex] = useState<ReaderStatePages['currentPageIndex']>(0);
|
||||||
const [pageToScrollToIndex, setPageToScrollToIndex] = useState<ReaderStatePages['pageToScrollToIndex']>(null);
|
const [pageToScrollToIndex, setPageToScrollToIndex] = useState<ReaderStatePages['pageToScrollToIndex']>(null);
|
||||||
const [pageUrls, setPageUrls] = useState<ReaderStatePages['pageUrls']>([]);
|
const [pageUrls, setPageUrls] = useState<ReaderStatePages['pageUrls']>([]);
|
||||||
const [pageLoadStates, setPageLoadStates] = useState<ReaderStatePages['pageLoadStates']>([{ loaded: false }]);
|
const [pageLoadStates, setPageLoadStates] = useState<ReaderStatePages['pageLoadStates']>([
|
||||||
|
{ url: '', loaded: false },
|
||||||
|
]);
|
||||||
const [pages, setPages] = useState<ReaderStatePages['pages']>([createPageData('', 0)]);
|
const [pages, setPages] = useState<ReaderStatePages['pages']>([createPageData('', 0)]);
|
||||||
const [transitionPageMode, setTransitionPageMode] = useState<ReaderStatePages['transitionPageMode']>(
|
const [transitionPageMode, setTransitionPageMode] = useState<ReaderStatePages['transitionPageMode']>(
|
||||||
ReaderTransitionPageMode.NONE,
|
ReaderTransitionPageMode.NONE,
|
||||||
|
|||||||
@@ -203,7 +203,7 @@ const BaseReader = ({
|
|||||||
setTotalPages(0);
|
setTotalPages(0);
|
||||||
setPages([createPageData('', 0)]);
|
setPages([createPageData('', 0)]);
|
||||||
setPageUrls([]);
|
setPageUrls([]);
|
||||||
setPageLoadStates([{ loaded: false }]);
|
setPageLoadStates([{ url: '', loaded: false }]);
|
||||||
|
|
||||||
setIsOverlayVisible(false);
|
setIsOverlayVisible(false);
|
||||||
|
|
||||||
@@ -224,11 +224,13 @@ const BaseReader = ({
|
|||||||
newPages.length - 1,
|
newPages.length - 1,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const newPageData = createPagesData(newPages);
|
||||||
|
|
||||||
setArePagesFetched(true);
|
setArePagesFetched(true);
|
||||||
setTotalPages(pagesPayload.chapter.pageCount);
|
setTotalPages(pagesPayload.chapter.pageCount);
|
||||||
setPages(createPagesData(newPages));
|
setPages(newPageData);
|
||||||
setPageUrls(newPages);
|
setPageUrls(newPages);
|
||||||
setPageLoadStates(newPages.map(() => ({ loaded: false })));
|
setPageLoadStates(newPageData.map(({ primary: { url } }) => ({ url, loaded: false })));
|
||||||
setCurrentPageIndex(initialReaderPageIndex);
|
setCurrentPageIndex(initialReaderPageIndex);
|
||||||
setPageToScrollToIndex(initialReaderPageIndex);
|
setPageToScrollToIndex(initialReaderPageIndex);
|
||||||
} else {
|
} else {
|
||||||
@@ -238,7 +240,7 @@ const BaseReader = ({
|
|||||||
setTotalPages(0);
|
setTotalPages(0);
|
||||||
setPages([createPageData('', 0)]);
|
setPages([createPageData('', 0)]);
|
||||||
setPageUrls([]);
|
setPageUrls([]);
|
||||||
setPageLoadStates([{ loaded: false }]);
|
setPageLoadStates([{ url: '', loaded: false }]);
|
||||||
}
|
}
|
||||||
|
|
||||||
setTransitionPageMode(ReaderTransitionPageMode.NONE);
|
setTransitionPageMode(ReaderTransitionPageMode.NONE);
|
||||||
|
|||||||
@@ -234,8 +234,8 @@ export interface ReaderPagerProps
|
|||||||
| 'retryFailedPagesKeyPrefix'
|
| 'retryFailedPagesKeyPrefix'
|
||||||
> {
|
> {
|
||||||
imageRefs: MutableRefObject<(HTMLElement | null)[]>;
|
imageRefs: MutableRefObject<(HTMLElement | null)[]>;
|
||||||
onLoad?: (pagesIndex: number, isPrimary?: boolean) => void;
|
onLoad?: (pagesIndex: number, url: string, isPrimary?: boolean) => void;
|
||||||
onError?: (pageIndex: number) => void;
|
onError?: (pageIndex: number, url: string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum PageInViewportType {
|
export enum PageInViewportType {
|
||||||
|
|||||||
@@ -31,8 +31,8 @@ export interface ReaderStatePages {
|
|||||||
setPageToScrollToIndex: React.Dispatch<React.SetStateAction<number | null>>;
|
setPageToScrollToIndex: React.Dispatch<React.SetStateAction<number | null>>;
|
||||||
pageUrls: string[];
|
pageUrls: string[];
|
||||||
setPageUrls: React.Dispatch<React.SetStateAction<string[]>>;
|
setPageUrls: React.Dispatch<React.SetStateAction<string[]>>;
|
||||||
pageLoadStates: { loaded: boolean; error?: boolean }[];
|
pageLoadStates: { url: string; loaded: boolean; error?: boolean }[];
|
||||||
setPageLoadStates: React.Dispatch<React.SetStateAction<{ loaded: boolean; error?: boolean }[]>>;
|
setPageLoadStates: React.Dispatch<React.SetStateAction<{ url: string; loaded: boolean; error?: boolean }[]>>;
|
||||||
pages: PageData[];
|
pages: PageData[];
|
||||||
setPages: React.Dispatch<React.SetStateAction<PageData[]>>;
|
setPages: React.Dispatch<React.SetStateAction<PageData[]>>;
|
||||||
transitionPageMode: ReaderTransitionPageMode;
|
transitionPageMode: ReaderTransitionPageMode;
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import {
|
|||||||
createPagesData,
|
createPagesData,
|
||||||
getScrollIntoViewInlineOption,
|
getScrollIntoViewInlineOption,
|
||||||
getScrollToXForReadingDirection,
|
getScrollToXForReadingDirection,
|
||||||
|
isPageOfOutdatedPageLoadStates,
|
||||||
isSpreadPage,
|
isSpreadPage,
|
||||||
} from '@/modules/reader/utils/ReaderPager.utils.tsx';
|
} from '@/modules/reader/utils/ReaderPager.utils.tsx';
|
||||||
import { ReaderStatePages } from '@/modules/reader/types/ReaderProgressBar.types.ts';
|
import { ReaderStatePages } from '@/modules/reader/types/ReaderProgressBar.types.ts';
|
||||||
@@ -130,9 +131,13 @@ export const createUpdateReaderPageLoadState =
|
|||||||
setPageLoadStates: ReaderStatePages['setPageLoadStates'],
|
setPageLoadStates: ReaderStatePages['setPageLoadStates'],
|
||||||
readingMode: ReadingMode,
|
readingMode: ReadingMode,
|
||||||
) =>
|
) =>
|
||||||
(pagesIndex: number, isPrimary: boolean = true) => {
|
(pagesIndex: number, url: string, isPrimary: boolean = true) => {
|
||||||
|
if (pagesIndex > actualPages.length - 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const page = actualPages[pagesIndex];
|
const page = actualPages[pagesIndex];
|
||||||
const { index, url } = isPrimary ? page.primary : page.secondary!;
|
const { index } = isPrimary ? page.primary : page.secondary!;
|
||||||
|
|
||||||
if (readingMode === ReadingMode.DOUBLE_PAGE) {
|
if (readingMode === ReadingMode.DOUBLE_PAGE) {
|
||||||
const img = new Image();
|
const img = new Image();
|
||||||
@@ -158,11 +163,17 @@ export const createUpdateReaderPageLoadState =
|
|||||||
}
|
}
|
||||||
|
|
||||||
setPageLoadStates((statePageLoadStates) => {
|
setPageLoadStates((statePageLoadStates) => {
|
||||||
if (statePageLoadStates[index].loaded) {
|
const pageLoadState = statePageLoadStates[index];
|
||||||
|
|
||||||
|
if (isPageOfOutdatedPageLoadStates(url, pageLoadState)) {
|
||||||
return statePageLoadStates;
|
return statePageLoadStates;
|
||||||
}
|
}
|
||||||
|
|
||||||
return statePageLoadStates.toSpliced(index, 1, { loaded: true });
|
if (pageLoadState.loaded) {
|
||||||
|
return statePageLoadStates;
|
||||||
|
}
|
||||||
|
|
||||||
|
return statePageLoadStates.toSpliced(index, 1, { url: pageLoadState.url, loaded: true });
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -524,3 +524,8 @@ export const getScrollToXForReadingDirection = (
|
|||||||
|
|
||||||
return getOptionForDirection(-element.scrollWidth, 0, themeDirectionForReadingDirection);
|
return getOptionForDirection(-element.scrollWidth, 0, themeDirectionForReadingDirection);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const isPageOfOutdatedPageLoadStates = (
|
||||||
|
url: string,
|
||||||
|
pageLoadState: ReaderStatePages['pageLoadStates'][number] | undefined,
|
||||||
|
): boolean => pageLoadState === undefined || pageLoadState.url !== url;
|
||||||
|
|||||||
Reference in New Issue
Block a user