Improve "chapter list" render performance

affected components:
- ChapterList
- ReaderChapterList
This commit is contained in:
schroda
2025-01-12 19:08:46 +01:00
parent e7c3c8609e
commit 97dba923b4
4 changed files with 28 additions and 17 deletions

View File

@@ -144,6 +144,11 @@ export const ChapterList = ({
const noChaptersFound = chapters.length === 0; const noChaptersFound = chapters.length === 0;
const noChaptersMatchingFilter = !noChaptersFound && visibleChapters.length === 0; const noChaptersMatchingFilter = !noChaptersFound && visibleChapters.length === 0;
const onSelect = useCallback(
(id: number, selected: boolean, selectRange?: boolean) => handleSelection(id, selected, { selectRange }),
[],
);
if (isLoading || (noChaptersFound && isRefreshing)) { if (isLoading || (noChaptersFound && isRefreshing)) {
return ( return (
<Stack sx={{ justifyContent: 'center', alignItems: 'center', position: 'relative', flexGrow: 1 }}> <Stack sx={{ justifyContent: 'center', alignItems: 'center', position: 'relative', flexGrow: 1 }}>
@@ -238,11 +243,8 @@ export const ChapterList = ({
<ChapterCard <ChapterCard
chapter={chapters[index]} chapter={chapters[index]}
selected={!areNoItemsSelected ? selectedItemIds.includes(chapters[index].id) : null} selected={!areNoItemsSelected ? selectedItemIds.includes(chapters[index].id) : null}
allChapters={chapters}
showChapterNumber={options.showChapterNumber} showChapterNumber={options.showChapterNumber}
onSelect={(selected, selectRange) => onSelect={onSelect}
handleSelection(chapters[index].id, selected, { selectRange })
}
/> />
)} )}
useWindowScroll={isMobileWidth} useWindowScroll={isMobileWidth}

View File

@@ -38,6 +38,9 @@ import {
import { defaultPromiseErrorHandler } from '@/lib/DefaultPromiseErrorHandler.ts'; import { defaultPromiseErrorHandler } from '@/lib/DefaultPromiseErrorHandler.ts';
import { useMetadataServerSettings } from '@/modules/settings/services/ServerSettingsMetadata.ts'; import { useMetadataServerSettings } from '@/modules/settings/services/ServerSettingsMetadata.ts';
import { ChapterCard } from '@/modules/chapter/components/cards/ChapterCard.tsx'; import { ChapterCard } from '@/modules/chapter/components/cards/ChapterCard.tsx';
import { requestManager } from '@/lib/requests/RequestManager.ts';
import { GetChaptersMangaQuery } from '@/lib/graphql/generated/graphql.ts';
import { GET_CHAPTERS_MANGA } from '@/lib/graphql/queries/ChapterQuery.ts';
type BaseProps = { onClose: () => void; selectable?: boolean }; type BaseProps = { onClose: () => void; selectable?: boolean };
@@ -50,7 +53,6 @@ type TChapter = ChapterIdInfo &
type SingleModeProps = { type SingleModeProps = {
chapter: TChapter; chapter: TChapter;
allChapters: TChapter[];
handleSelection?: SelectableCollectionReturnType<TChapter['id']>['handleSelection']; handleSelection?: SelectableCollectionReturnType<TChapter['id']>['handleSelection'];
canBeDownloaded: boolean; canBeDownloaded: boolean;
}; };
@@ -65,7 +67,6 @@ type Props =
export const ChapterActionMenuItems = ({ export const ChapterActionMenuItems = ({
chapter, chapter,
allChapters,
handleSelection, handleSelection,
canBeDownloaded = false, canBeDownloaded = false,
selectedChapters = [], selectedChapters = [],
@@ -77,6 +78,16 @@ export const ChapterActionMenuItems = ({
const isSingleMode = !!chapter; const isSingleMode = !!chapter;
const { isDownloaded, isRead, isBookmarked } = chapter ?? {}; const { isDownloaded, isRead, isBookmarked } = chapter ?? {};
const mangaChaptersResponse = requestManager.useGetMangaChapters<GetChaptersMangaQuery>(
GET_CHAPTERS_MANGA,
chapter?.mangaId ?? -1,
{
skip: !chapter,
fetchPolicy: 'cache-only',
},
);
const allChapters = mangaChaptersResponse.data?.chapters.nodes ?? [];
const { const {
settings: { deleteChaptersWithBookmark }, settings: { deleteChaptersWithBookmark },
} = useMetadataServerSettings(); } = useMetadataServerSettings();

View File

@@ -17,7 +17,7 @@ import CardContent from '@mui/material/CardContent';
import IconButton from '@mui/material/IconButton'; import IconButton from '@mui/material/IconButton';
import { useTheme } from '@mui/material/styles'; import { useTheme } from '@mui/material/styles';
import Typography from '@mui/material/Typography'; import Typography from '@mui/material/Typography';
import React, { MouseEvent, TouchEvent, useRef } from 'react'; import React, { memo, MouseEvent, TouchEvent, useRef } from 'react';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import PopupState, { bindMenu, bindTrigger } from 'material-ui-popup-state'; import PopupState, { bindMenu, bindTrigger } from 'material-ui-popup-state';
@@ -51,15 +51,14 @@ type TChapter = ChapterIdInfo &
interface IProps { interface IProps {
mode?: 'manga.page' | 'reader'; mode?: 'manga.page' | 'reader';
chapter: TChapter; chapter: TChapter;
allChapters: TChapter[];
showChapterNumber: boolean; showChapterNumber: boolean;
onSelect: (selected: boolean, isShiftKey?: boolean) => void; onSelect: (id: number, selected: boolean, isShiftKey?: boolean) => void;
selected: boolean | null; selected: boolean | null;
selectable?: boolean; selectable?: boolean;
isActiveChapter?: boolean; // reader isActiveChapter?: boolean; // reader
} }
export const ChapterCard: React.FC<IProps> = (props: IProps) => { export const ChapterCard = memo((props: IProps) => {
const { t } = useTranslation(); const { t } = useTranslation();
const theme = useTheme(); const theme = useTheme();
@@ -68,7 +67,6 @@ export const ChapterCard: React.FC<IProps> = (props: IProps) => {
const { const {
mode = 'manga.page', mode = 'manga.page',
chapter, chapter,
allChapters,
showChapterNumber, showChapterNumber,
onSelect, onSelect,
selected, selected,
@@ -84,7 +82,7 @@ export const ChapterCard: React.FC<IProps> = (props: IProps) => {
event.preventDefault(); event.preventDefault();
event.stopPropagation(); event.stopPropagation();
onSelect(!selected, event.shiftKey); onSelect(chapter.id, !selected, event.shiftKey);
}; };
const handleClickOpenMenu = ( const handleClickOpenMenu = (
@@ -204,8 +202,7 @@ export const ChapterCard: React.FC<IProps> = (props: IProps) => {
<ChapterActionMenuItems <ChapterActionMenuItems
onClose={onClose} onClose={onClose}
chapter={chapter} chapter={chapter}
allChapters={allChapters} handleSelection={() => onSelect(chapter.id, true)}
handleSelection={() => onSelect(true)}
canBeDownloaded={Chapters.isDownloadable(chapter)} canBeDownloaded={Chapters.isDownloadable(chapter)}
selectable={selectable} selectable={selectable}
/> />
@@ -216,4 +213,4 @@ export const ChapterCard: React.FC<IProps> = (props: IProps) => {
)} )}
</PopupState> </PopupState>
); );
}; });

View File

@@ -11,6 +11,8 @@ import { useMemo } from 'react';
import { ChapterCard } from '@/modules/chapter/components/cards/ChapterCard.tsx'; import { ChapterCard } from '@/modules/chapter/components/cards/ChapterCard.tsx';
import { ReaderStateChapters } from '@/modules/reader/types/Reader.types.ts'; import { ReaderStateChapters } from '@/modules/reader/types/Reader.types.ts';
const onSelectNoop = () => {};
export const ReaderChapterList = ({ export const ReaderChapterList = ({
currentChapter, currentChapter,
chapters, chapters,
@@ -35,10 +37,9 @@ export const ReaderChapterList = ({
key={chapters[index].id} key={chapters[index].id}
mode="reader" mode="reader"
chapter={chapters[index]} chapter={chapters[index]}
allChapters={chapters}
showChapterNumber={false} showChapterNumber={false}
selected={null} selected={null}
onSelect={() => undefined} onSelect={onSelectNoop}
selectable={false} selectable={false}
isActiveChapter={index === currentChapterIndex} isActiveChapter={index === currentChapterIndex}
/> />