Improve memoization of reader desktop nav bar

This commit is contained in:
schroda
2024-12-21 15:36:23 +01:00
parent f1f660a546
commit 948e2564fa
5 changed files with 171 additions and 146 deletions

View File

@@ -33,8 +33,7 @@ import { ReaderService } from '@/modules/reader/services/ReaderService.ts';
import { LoadingPlaceholder } from '@/modules/core/components/placeholder/LoadingPlaceholder.tsx'; import { LoadingPlaceholder } from '@/modules/core/components/placeholder/LoadingPlaceholder.tsx';
import { MangaIdInfo } from '@/modules/manga/Manga.types.ts'; import { MangaIdInfo } from '@/modules/manga/Manga.types.ts';
import { NavbarContextType } from '@/modules/navigation-bar/NavigationBar.types.ts'; import { NavbarContextType } from '@/modules/navigation-bar/NavigationBar.types.ts';
import { ReaderStateChapters, TReaderStateMangaContext } from '@/modules/reader/types/Reader.types.ts'; import { IReaderSettings, ReaderStateChapters, TReaderStateMangaContext } from '@/modules/reader/types/Reader.types.ts';
import { ReaderStatePages } from '@/modules/reader/types/ReaderProgressBar.types.ts';
import { withPropsFrom } from '@/modules/core/hoc/withPropsFrom.tsx'; import { withPropsFrom } from '@/modules/core/hoc/withPropsFrom.tsx';
const useGetPreviousNavBarStaticValue = (isVisible: boolean, isStaticNav: boolean) => { const useGetPreviousNavBarStaticValue = (isVisible: boolean, isStaticNav: boolean) => {
@@ -65,20 +64,13 @@ const BaseReaderNavBarDesktop = ({
currentChapter, currentChapter,
previousChapter, previousChapter,
nextChapter, nextChapter,
pages, isStaticNav,
currentPageIndex,
pageLoadStates,
setPageLoadStates,
setRetryFailedPagesKeyPrefix,
exit, exit,
}: ReaderNavBarDesktopProps & }: ReaderNavBarDesktopProps &
Pick<NavbarContextType, 'setReaderNavBarWidth'> & Pick<NavbarContextType, 'setReaderNavBarWidth'> &
Pick<TReaderStateMangaContext, 'manga'> & Pick<TReaderStateMangaContext, 'manga'> &
Pick<ReaderStateChapters, 'currentChapter' | 'previousChapter' | 'nextChapter' | 'chapters'> & Pick<ReaderStateChapters, 'currentChapter' | 'previousChapter' | 'nextChapter' | 'chapters'> &
Pick< Pick<IReaderSettings, 'isStaticNav'> & {
ReaderStatePages,
'pages' | 'currentPageIndex' | 'pageLoadStates' | 'setPageLoadStates' | 'setRetryFailedPagesKeyPrefix'
> & {
exit: ReturnType<typeof ReaderService.useExit>; exit: ReturnType<typeof ReaderService.useExit>;
}) => { }) => {
const { t } = useTranslation(); const { t } = useTranslation();
@@ -86,29 +78,28 @@ const BaseReaderNavBarDesktop = ({
const getOptionForDirection = useGetOptionForDirection(); const getOptionForDirection = useGetOptionForDirection();
const updateReaderSettings = ReaderService.useCreateUpdateSetting(manga ?? DEFAULT_MANGA); const updateReaderSettings = ReaderService.useCreateUpdateSetting(manga ?? DEFAULT_MANGA);
const settings = ReaderService.useSettings();
const [navBarElement, setNavBarElement] = useState<HTMLDivElement | null>(); const [navBarElement, setNavBarElement] = useState<HTMLDivElement | null>();
useResizeObserver( useResizeObserver(
navBarElement, navBarElement,
useCallback(() => { useCallback(() => {
if (!settings?.isStaticNav) { if (!isStaticNav) {
return; return;
} }
setReaderNavBarWidth(navBarElement!.offsetWidth); setReaderNavBarWidth(navBarElement!.offsetWidth);
}, [navBarElement, settings?.isStaticNav]), }, [navBarElement, isStaticNav]),
); );
useLayoutEffect(() => () => setReaderNavBarWidth(0), []); useLayoutEffect(() => () => setReaderNavBarWidth(0), []);
const wasNavBarStatic = useGetPreviousNavBarStaticValue(isVisible, settings.isStaticNav); const wasNavBarStatic = useGetPreviousNavBarStaticValue(isVisible, isStaticNav);
const changedNavBarStaticValue = wasNavBarStatic && isVisible; const changedNavBarStaticValue = wasNavBarStatic && isVisible;
const drawerTransitionDuration = changedNavBarStaticValue ? 0 : undefined; const drawerTransitionDuration = changedNavBarStaticValue ? 0 : undefined;
return ( return (
<Drawer <Drawer
variant={settings.isStaticNav ? 'permanent' : 'persistent'} variant={isStaticNav ? 'permanent' : 'persistent'}
open={isVisible || settings.isStaticNav} open={isVisible || isStaticNav}
transitionDuration={drawerTransitionDuration} transitionDuration={drawerTransitionDuration}
PaperProps={{ PaperProps={{
ref: (ref: HTMLDivElement | null) => setNavBarElement(ref), ref: (ref: HTMLDivElement | null) => setNavBarElement(ref),
@@ -126,9 +117,9 @@ const BaseReaderNavBarDesktop = ({
<IconButton <IconButton
onClick={() => { onClick={() => {
setReaderNavBarWidth(0); setReaderNavBarWidth(0);
updateReaderSettings('isStaticNav', !settings.isStaticNav); updateReaderSettings('isStaticNav', !isStaticNav);
}} }}
color={settings.isStaticNav ? 'primary' : 'inherit'} color={isStaticNav ? 'primary' : 'inherit'}
> >
<PushPinIcon /> <PushPinIcon />
</IconButton> </IconButton>
@@ -142,12 +133,7 @@ const BaseReaderNavBarDesktop = ({
chapterTitle={currentChapter.name} chapterTitle={currentChapter.name}
scanlator={currentChapter.scanlator} scanlator={currentChapter.scanlator}
/> />
<ReaderNavBarDesktopActions <ReaderNavBarDesktopActions />
currentChapter={currentChapter}
pageLoadStates={pageLoadStates}
setPageLoadStates={setPageLoadStates}
setRetryFailedPagesKeyPrefix={setRetryFailedPagesKeyPrefix}
/>
</> </>
) : ( ) : (
<LoadingPlaceholder /> <LoadingPlaceholder />
@@ -155,7 +141,7 @@ const BaseReaderNavBarDesktop = ({
</Stack> </Stack>
<Stack sx={{ p: 2, gap: 2 }}> <Stack sx={{ p: 2, gap: 2 }}>
<Stack sx={{ gap: 1 }}> <Stack sx={{ gap: 1 }}>
<ReaderNavBarDesktopPageNavigation currentPageIndex={currentPageIndex} pages={pages} /> <ReaderNavBarDesktopPageNavigation />
<ReaderNavBarDesktopChapterNavigation <ReaderNavBarDesktopChapterNavigation
chapters={chapters} chapters={chapters}
currentChapter={currentChapter} currentChapter={currentChapter}
@@ -164,13 +150,7 @@ const BaseReaderNavBarDesktop = ({
/> />
</Stack> </Stack>
<Divider /> <Divider />
<ReaderNavBarDesktopQuickSettings <ReaderNavBarDesktopQuickSettings openSettings={openSettings} />
settings={settings}
updateSetting={updateReaderSettings}
openSettings={openSettings}
isDefaultable
onDefault={(...args) => manga && ReaderService.deleteSetting(manga, ...args)}
/>
</Stack> </Stack>
</ReaderNavContainer> </ReaderNavContainer>
</Drawer> </Drawer>
@@ -184,6 +164,7 @@ export const ReaderNavBarDesktop = withPropsFrom(
useReaderStateMangaContext, useReaderStateMangaContext,
useReaderStateChaptersContext, useReaderStateChaptersContext,
userReaderStatePagesContext, userReaderStatePagesContext,
ReaderService.useSettingsWithoutDefaultFlag,
() => ({ exit: ReaderService.useExit() }), () => ({ exit: ReaderService.useExit() }),
], ],
[ [
@@ -193,11 +174,7 @@ export const ReaderNavBarDesktop = withPropsFrom(
'currentChapter', 'currentChapter',
'previousChapter', 'previousChapter',
'nextChapter', 'nextChapter',
'pages', 'isStaticNav',
'currentPageIndex',
'pageLoadStates',
'setPageLoadStates',
'setRetryFailedPagesKeyPrefix',
'exit', 'exit',
], ],
); );

View File

@@ -15,7 +15,7 @@ import BookmarkBorderIcon from '@mui/icons-material/BookmarkBorder';
import OpenInNewIcon from '@mui/icons-material/OpenInNew'; import OpenInNewIcon from '@mui/icons-material/OpenInNew';
import DownloadIcon from '@mui/icons-material/Download'; import DownloadIcon from '@mui/icons-material/Download';
import ReplayIcon from '@mui/icons-material/Replay'; import ReplayIcon from '@mui/icons-material/Replay';
import { useMemo, useRef } from 'react'; import { memo, useMemo, useRef } from 'react';
import DeleteIcon from '@mui/icons-material/Delete'; import DeleteIcon from '@mui/icons-material/Delete';
import { actionToTranslationKey, ChapterAction, Chapters } from '@/modules/chapter/services/Chapters.ts'; import { actionToTranslationKey, ChapterAction, Chapters } from '@/modules/chapter/services/Chapters.ts';
import { ReaderStateChapters } from '@/modules/reader/types/Reader.types.ts'; import { ReaderStateChapters } from '@/modules/reader/types/Reader.types.ts';
@@ -23,6 +23,9 @@ import { requestManager } from '@/lib/requests/RequestManager.ts';
import { DownloadStateIndicator } from '@/modules/core/components/DownloadStateIndicator.tsx'; import { DownloadStateIndicator } from '@/modules/core/components/DownloadStateIndicator.tsx';
import { DownloadStatusFieldsFragment } from '@/lib/graphql/generated/graphql.ts'; import { DownloadStatusFieldsFragment } from '@/lib/graphql/generated/graphql.ts';
import { ReaderStatePages } from '@/modules/reader/types/ReaderProgressBar.types.ts'; import { ReaderStatePages } from '@/modules/reader/types/ReaderProgressBar.types.ts';
import { withPropsFrom } from '@/modules/core/hoc/withPropsFrom.tsx';
import { useReaderStateChaptersContext } from '@/modules/reader/contexts/state/ReaderStateChaptersContext.tsx';
import { userReaderStatePagesContext } from '@/modules/reader/contexts/state/ReaderStatePagesContext.tsx';
const DownloadButton = ({ const DownloadButton = ({
currentChapter, currentChapter,
@@ -59,7 +62,8 @@ const DownloadButton = ({
); );
}; };
export const ReaderNavBarDesktopActions = ({ const BaseReaderNavBarDesktopActions = memo(
({
currentChapter, currentChapter,
pageLoadStates, pageLoadStates,
setPageLoadStates, setPageLoadStates,
@@ -85,7 +89,9 @@ export const ReaderNavBarDesktopActions = ({
[pageLoadStates], [pageLoadStates],
); );
const bookmarkAction: Extract<ChapterAction, 'unbookmark' | 'bookmark'> = isBookmarked ? 'unbookmark' : 'bookmark'; const bookmarkAction: Extract<ChapterAction, 'unbookmark' | 'bookmark'> = isBookmarked
? 'unbookmark'
: 'bookmark';
return ( return (
<Stack sx={{ flexDirection: 'row', justifyContent: 'center', gap: 1 }}> <Stack sx={{ flexDirection: 'row', justifyContent: 'center', gap: 1 }}>
@@ -111,10 +117,23 @@ export const ReaderNavBarDesktopActions = ({
</Tooltip> </Tooltip>
<DownloadButton currentChapter={currentChapter} downloadChapter={downloadChapter} /> <DownloadButton currentChapter={currentChapter} downloadChapter={downloadChapter} />
<Tooltip title={t('chapter.action.label.open_on_source')}> <Tooltip title={t('chapter.action.label.open_on_source')}>
<IconButton disabled={!realUrl} href={realUrl ?? ''} rel="noreferrer" target="_blank" color="inherit"> <IconButton
disabled={!realUrl}
href={realUrl ?? ''}
rel="noreferrer"
target="_blank"
color="inherit"
>
<OpenInNewIcon /> <OpenInNewIcon />
</IconButton> </IconButton>
</Tooltip> </Tooltip>
</Stack> </Stack>
); );
}; },
);
export const ReaderNavBarDesktopActions = withPropsFrom(
BaseReaderNavBarDesktopActions,
[useReaderStateChaptersContext, userReaderStatePagesContext],
['currentChapter', 'pageLoadStates', 'setPageLoadStates', 'setRetryFailedPagesKeyPrefix'],
);

View File

@@ -11,10 +11,12 @@ import Tooltip from '@mui/material/Tooltip';
import Link from '@mui/material/Link'; import Link from '@mui/material/Link';
import { Link as RouterLink } from 'react-router-dom'; import { Link as RouterLink } from 'react-router-dom';
import { memo } from 'react';
import { TypographyMaxLines } from '@/modules/core/components/TypographyMaxLines'; import { TypographyMaxLines } from '@/modules/core/components/TypographyMaxLines';
import { AppRoutes } from '@/modules/core/AppRoute.constants.ts'; import { AppRoutes } from '@/modules/core/AppRoute.constants.ts';
export const ReaderNavBarDesktopMetadata = ({ export const ReaderNavBarDesktopMetadata = memo(
({
mangaId, mangaId,
mangaTitle, mangaTitle,
chapterTitle, chapterTitle,
@@ -56,4 +58,5 @@ export const ReaderNavBarDesktopMetadata = ({
</Tooltip> </Tooltip>
)} )}
</Stack> </Stack>
),
); );

View File

@@ -22,6 +22,7 @@ import { ReaderNavBarDesktopNextPreviousButton } from '@/modules/reader/componen
import { READING_DIRECTION_TO_THEME_DIRECTION } from '@/modules/reader/constants/ReaderSettings.constants.tsx'; import { READING_DIRECTION_TO_THEME_DIRECTION } from '@/modules/reader/constants/ReaderSettings.constants.tsx';
import { IReaderSettings } from '@/modules/reader/types/Reader.types.ts'; import { IReaderSettings } from '@/modules/reader/types/Reader.types.ts';
import { withPropsFrom } from '@/modules/core/hoc/withPropsFrom.tsx'; import { withPropsFrom } from '@/modules/core/hoc/withPropsFrom.tsx';
import { userReaderStatePagesContext } from '@/modules/reader/contexts/state/ReaderStatePagesContext.tsx';
const BaseReaderNavBarDesktopPageNavigation = ({ const BaseReaderNavBarDesktopPageNavigation = ({
currentPageIndex, currentPageIndex,
@@ -81,6 +82,10 @@ const BaseReaderNavBarDesktopPageNavigation = ({
export const ReaderNavBarDesktopPageNavigation = withPropsFrom( export const ReaderNavBarDesktopPageNavigation = withPropsFrom(
memo(BaseReaderNavBarDesktopPageNavigation), memo(BaseReaderNavBarDesktopPageNavigation),
[() => ({ openPage: ReaderControls.useOpenPage() }), ReaderService.useSettingsWithoutDefaultFlag], [
['readingDirection', 'openPage'], userReaderStatePagesContext,
() => ({ openPage: ReaderControls.useOpenPage() }),
ReaderService.useSettingsWithoutDefaultFlag,
],
['currentPageIndex', 'pages', 'readingDirection', 'openPage'],
); );

View File

@@ -14,25 +14,40 @@ import { ReaderNavBarDesktopPageScale } from '@/modules/reader/components/overla
import { ReaderNavBarDesktopReadingMode } from '@/modules/reader/components/overlay/navigation/desktop/quick-settings/ReaderNavBarDesktopReadingMode.tsx'; import { ReaderNavBarDesktopReadingMode } from '@/modules/reader/components/overlay/navigation/desktop/quick-settings/ReaderNavBarDesktopReadingMode.tsx';
import { ReaderNavBarDesktopOffsetDoubleSpread } from '@/modules/reader/components/overlay/navigation/desktop/quick-settings/ReaderNavBarDesktopOffsetDoubleSpread.tsx'; import { ReaderNavBarDesktopOffsetDoubleSpread } from '@/modules/reader/components/overlay/navigation/desktop/quick-settings/ReaderNavBarDesktopOffsetDoubleSpread.tsx';
import { ReaderNavBarDesktopReadingDirection } from '@/modules/reader/components/overlay/navigation/desktop/quick-settings/ReaderNavBarDesktopReadingDirection.tsx'; import { ReaderNavBarDesktopReadingDirection } from '@/modules/reader/components/overlay/navigation/desktop/quick-settings/ReaderNavBarDesktopReadingDirection.tsx';
import { ReaderSettingsTypeProps } from '@/modules/reader/types/Reader.types.ts'; import { IReaderSettingsWithDefaultFlag, TReaderStateMangaContext } from '@/modules/reader/types/Reader.types.ts';
import { ReaderNavBarDesktopProps } from '@/modules/reader/types/ReaderOverlay.types.ts'; import { ReaderNavBarDesktopProps } from '@/modules/reader/types/ReaderOverlay.types.ts';
import { ReaderService } from '@/modules/reader/services/ReaderService.ts';
import { MangaIdInfo } from '@/modules/manga/Manga.types.ts';
import { withPropsFrom } from '@/modules/core/hoc/withPropsFrom.tsx';
import { useReaderStateMangaContext } from '@/modules/reader/contexts/state/ReaderStateMangaContext.tsx';
export const ReaderNavBarDesktopQuickSettings = ({ const DEFAULT_MANGA: MangaIdInfo = { id: -1 };
settings: { readingMode, shouldOffsetDoubleSpreads, pageScaleMode, shouldStretchPage, readingDirection }, const BaseReaderNavBarDesktopQuickSettings = ({
updateSetting, manga,
readingMode,
shouldOffsetDoubleSpreads,
pageScaleMode,
shouldStretchPage,
readingDirection,
openSettings, openSettings,
isDefaultable, }: Pick<TReaderStateMangaContext, 'manga'> &
onDefault, Pick<ReaderNavBarDesktopProps, 'openSettings'> &
}: ReaderSettingsTypeProps & Pick<ReaderNavBarDesktopProps, 'openSettings'>) => { Pick<
IReaderSettingsWithDefaultFlag,
'readingMode' | 'shouldOffsetDoubleSpreads' | 'pageScaleMode' | 'shouldStretchPage' | 'readingDirection'
>) => {
const { t } = useTranslation(); const { t } = useTranslation();
const updateSetting = ReaderService.useCreateUpdateSetting(manga ?? DEFAULT_MANGA);
const deleteSetting = ReaderService.useCreateDeleteSetting(manga ?? DEFAULT_MANGA);
return ( return (
<Stack sx={{ gap: 1 }}> <Stack sx={{ gap: 1 }}>
<ReaderNavBarDesktopReadingMode <ReaderNavBarDesktopReadingMode
readingMode={readingMode} readingMode={readingMode}
setReadingMode={(value) => updateSetting('readingMode', value)} setReadingMode={(value) => updateSetting('readingMode', value)}
isDefaultable={isDefaultable} isDefaultable
onDefault={() => onDefault?.('readingMode')} onDefault={() => deleteSetting('readingMode')}
/> />
<ReaderNavBarDesktopOffsetDoubleSpread <ReaderNavBarDesktopOffsetDoubleSpread
readingMode={readingMode.value} readingMode={readingMode.value}
@@ -43,14 +58,14 @@ export const ReaderNavBarDesktopQuickSettings = ({
pageScaleMode={pageScaleMode} pageScaleMode={pageScaleMode}
shouldStretchPage={shouldStretchPage} shouldStretchPage={shouldStretchPage}
updateSetting={updateSetting} updateSetting={updateSetting}
isDefaultable={isDefaultable} isDefaultable
onDefault={() => onDefault?.('pageScaleMode')} onDefault={() => deleteSetting('pageScaleMode')}
/> />
<ReaderNavBarDesktopReadingDirection <ReaderNavBarDesktopReadingDirection
readingDirection={readingDirection} readingDirection={readingDirection}
setReadingDirection={(value) => updateSetting('readingDirection', value)} setReadingDirection={(value) => updateSetting('readingDirection', value)}
isDefaultable={isDefaultable} isDefaultable
onDefault={() => onDefault?.('readingDirection')} onDefault={() => deleteSetting('readingDirection')}
/> />
<Button <Button
onClick={() => openSettings()} onClick={() => openSettings()}
@@ -64,3 +79,9 @@ export const ReaderNavBarDesktopQuickSettings = ({
</Stack> </Stack>
); );
}; };
export const ReaderNavBarDesktopQuickSettings = withPropsFrom(
BaseReaderNavBarDesktopQuickSettings,
[useReaderStateMangaContext, ReaderService.useSettings],
['manga', 'readingMode', 'shouldOffsetDoubleSpreads', 'pageScaleMode', 'shouldStretchPage', 'readingDirection'],
);