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