Improve memoization of reader "progress bar slot" rendering

This commit is contained in:
schroda
2024-12-25 23:50:58 +01:00
parent 5220f8ca44
commit 500ee42662
4 changed files with 137 additions and 80 deletions

View File

@@ -71,6 +71,8 @@ const BaseReaderProgressBar = ({
}) => {
const progressBarRef = useRef<HTMLDivElement | null>(null);
const currentPagesIndex = useMemo(() => getPage(currentPageIndex, pages).pagesIndex, [currentPageIndex, pages]);
const isHorizontalPosition = getProgressBarPositionInfo(progressBarPosition).isHorizontal;
const currentPage = useMemo(() => getPage(currentPageIndex, pages), [currentPageIndex, pages]);
const getOptionForDirection = useCallback(
@@ -157,14 +159,19 @@ const BaseReaderProgressBar = ({
<ReaderProgressBarSlotsContainer {...slotProps?.progressBarSlotsContainer}>
{pages.map((page, pagesIndex) => (
<ReaderProgressBarSlotWrapper
{...slotProps?.progressBarSlot}
key={page.primary.index}
page={page}
pagesIndex={pagesIndex}
pageLoadStates={pageLoadStates}
isCurrentPage={pagesIndex === currentPagesIndex}
isLeadingPage={pagesIndex < currentPagesIndex}
isTrailingPage={pagesIndex > currentPagesIndex}
totalPages={pages.length}
primaryPageLoadState={pageLoadStates[page.primary.index].loaded}
secondaryPageLoadState={
!!page.secondary && pageLoadStates[page.secondary.index].loaded
}
createProgressBarSlot={createProgressBarSlot}
{...slotProps?.progressBarSlot}
isFirstPage={pagesIndex === 0}
isLastPage={pagesIndex === pages.length - 1}
/>
))}
<ProgressBarHighlightReadPages

View File

@@ -7,42 +7,87 @@
*/
import Box, { BoxProps } from '@mui/material/Box';
import { memo, ReactNode } from 'react';
import { memo, ReactNode, useMemo } from 'react';
import { styled } from '@mui/material/styles';
import { ReaderProgressBarProps } from '@/modules/reader/types/ReaderProgressBar.types.ts';
import { shouldForwardProp } from '@/modules/core/utils/ShouldForwardProp.ts';
type StyledWrapperProps = {
isFirstPage: boolean;
isLastPage: boolean;
};
const StyledWrapper = memo(
styled(Box, {
shouldForwardProp: shouldForwardProp<StyledWrapperProps>(['isFirstPage', 'isLastPage']),
})<BoxProps & StyledWrapperProps>(({ isFirstPage, isLastPage }) => ({
flexGrow: 1,
height: '100%',
cursor: 'pointer',
borderLeftWidth: isFirstPage ? 0 : undefined,
borderRightWidth: isLastPage ? 0 : undefined,
})),
);
export const ReaderProgressBarSlotWrapper = memo(
({
page,
pagesIndex,
pageLoadStates,
isFirstPage,
isLastPage,
isCurrentPage,
isLeadingPage,
isTrailingPage,
totalPages,
primaryPageLoadState,
secondaryPageLoadState,
createProgressBarSlot,
...boxProps
}: {
page: ReaderProgressBarProps['pages'][number];
pagesIndex: number;
pageLoadStates: ReaderProgressBarProps['pageLoadStates'];
isFirstPage: boolean;
isLastPage: boolean;
isCurrentPage: boolean;
isLeadingPage: boolean;
isTrailingPage: boolean;
totalPages: number;
primaryPageLoadState: ReaderProgressBarProps['pageLoadStates'][number]['loaded'];
secondaryPageLoadState: ReaderProgressBarProps['pageLoadStates'][number]['loaded'];
createProgressBarSlot: (
page: ReaderProgressBarProps['pages'][number],
pageLoadStates: ReaderProgressBarProps['pageLoadStates'],
pagesIndex: number,
primaryPageLoadState: ReaderProgressBarProps['pageLoadStates'][number]['loaded'],
secondaryPageLoadState: ReaderProgressBarProps['pageLoadStates'][number]['loaded'],
isCurrentPage: boolean,
isLeadingPage: boolean,
isTrailingPage: boolean,
totalPages: number,
) => ReactNode;
} & BoxProps) => (
<Box
{...boxProps}
sx={{
flexGrow: 1,
height: '100%',
cursor: 'pointer',
...boxProps?.sx,
borderLeftWidth: isFirstPage ? 0 : undefined,
borderRightWidth: isLastPage ? 0 : undefined,
}}
>
{createProgressBarSlot(page, pageLoadStates, pagesIndex)}
</Box>
),
} & BoxProps) => {
const slot = useMemo(
() =>
createProgressBarSlot(
page,
pagesIndex,
primaryPageLoadState,
secondaryPageLoadState,
isCurrentPage,
isLeadingPage,
isTrailingPage,
totalPages,
),
[
page,
pagesIndex,
primaryPageLoadState,
secondaryPageLoadState,
isCurrentPage,
isLeadingPage,
isTrailingPage,
totalPages,
],
);
return (
<StyledWrapper {...boxProps} isFirstPage={pagesIndex === 0} isLastPage={pagesIndex === totalPages - 1}>
{slot}
</StyledWrapper>
);
},
);

View File

@@ -12,13 +12,13 @@ import SkipNextIcon from '@mui/icons-material/SkipNext';
import Stack from '@mui/material/Stack';
import { alpha } from '@mui/material/styles';
import Box from '@mui/material/Box';
import { memo, useLayoutEffect } from 'react';
import { memo, useCallback, useLayoutEffect } from 'react';
import { ReaderProgressBar } from '@/modules/reader/components/overlay/progress-bar/ReaderProgressBar.tsx';
import { ReaderProgressBarSlot } from '@/modules/reader/components/overlay/progress-bar/ReaderProgressBarSlot.tsx';
import { userReaderStatePagesContext } from '@/modules/reader/contexts/state/ReaderStatePagesContext.tsx';
import { useReaderStateChaptersContext } from '@/modules/reader/contexts/state/ReaderStateChaptersContext.tsx';
import { ReaderService } from '@/modules/reader/services/ReaderService.ts';
import { getNextIndexFromPage, getPage } from '@/modules/reader/utils/ReaderProgressBar.utils.tsx';
import { getPage } from '@/modules/reader/utils/ReaderProgressBar.utils.tsx';
import { getOptionForDirection } from '@/modules/theme/services/ThemeCreator.ts';
import { ProgressBarPosition, ReaderResumeMode, ReaderStateChapters } from '@/modules/reader/types/Reader.types.ts';
import { ReaderProgressBarDirectionWrapper } from '@/modules/reader/components/overlay/progress-bar/ReaderProgressBarDirectionWrapper.tsx';
@@ -75,39 +75,42 @@ const BaseMobileReaderProgressBar = ({
<ReaderProgressBar
progressBarPosition={ProgressBarPosition.BOTTOM}
{...pagesState}
createProgressBarSlot={(page) => (
<ReaderProgressBarSlot
pageName={page.name}
progressBarPosition={ProgressBarPosition.BOTTOM}
slotProps={{
box: {
sx: {
display: 'flex',
alignItems: 'center',
justifyContent: 'end',
position: 'relative',
backgroundColor: 'background.default',
createProgressBarSlot={useCallback(
(page, pagesIndex, _, __, ___, ____, isTrailingPage) => (
<ReaderProgressBarSlot
pageName={page.name}
progressBarPosition={ProgressBarPosition.BOTTOM}
slotProps={{
box: {
sx: {
display: 'flex',
alignItems: 'center',
justifyContent: 'end',
position: 'relative',
backgroundColor: 'background.default',
},
},
},
}}
>
<Box
sx={{
position: 'absolute',
top: '50%',
transform: 'translateY(-50%)',
right: '2px',
width: '2px',
height: '2px',
borderRadius: 100,
backgroundColor: 'background.paper',
...applyStyles(getNextIndexFromPage(page) > currentPageIndex, {
backgroundColor: 'primary.main',
}),
zIndex: 1,
}}
/>
</ReaderProgressBarSlot>
>
<Box
sx={{
position: 'absolute',
top: '50%',
transform: 'translateY(-50%)',
right: '2px',
width: '2px',
height: '2px',
borderRadius: 100,
backgroundColor: 'background.paper',
...applyStyles(isTrailingPage, {
backgroundColor: 'primary.main',
}),
zIndex: 1,
}}
/>
</ReaderProgressBarSlot>
),
[],
)}
slotProps={{
container: {

View File

@@ -7,13 +7,13 @@
*/
import { useTheme } from '@mui/material/styles';
import { memo } from 'react';
import { memo, useCallback } from 'react';
import { ReaderProgressBar } from '@/modules/reader/components/overlay/progress-bar/ReaderProgressBar.tsx';
import { userReaderStatePagesContext } from '@/modules/reader/contexts/state/ReaderStatePagesContext.tsx';
import { ReaderService } from '@/modules/reader/services/ReaderService.ts';
import { IReaderSettings, ProgressBarType, TReaderScrollbarContext } from '@/modules/reader/types/Reader.types.ts';
import { applyStyles } from '@/modules/core/utils/ApplyStyles.ts';
import { getPage, getProgressBarPositionInfo } from '@/modules/reader/utils/ReaderProgressBar.utils.tsx';
import { getProgressBarPositionInfo } from '@/modules/reader/utils/ReaderProgressBar.utils.tsx';
import { ReaderProgressBarDirectionWrapper } from '@/modules/reader/components/overlay/progress-bar/ReaderProgressBarDirectionWrapper.tsx';
import { TReaderProgressBarContext } from '@/modules/reader/types/ReaderProgressBar.types.ts';
import { NavbarContextType } from '@/modules/navigation-bar/NavigationBar.types.ts';
@@ -42,9 +42,7 @@ const BaseStandardReaderProgressBar = ({
}) => {
const theme = useTheme();
const pagesState = userReaderStatePagesContext();
const { currentPageIndex, pages, totalPages } = pagesState;
const currentPagesIndex = getPage(currentPageIndex, pages).pagesIndex;
const { totalPages } = pagesState;
const { isBottom, isLeft, isRight, isVertical, isHorizontal } = getProgressBarPositionInfo(progressBarPosition);
@@ -59,30 +57,34 @@ const BaseStandardReaderProgressBar = ({
<ReaderProgressBar
{...pagesState}
progressBarPosition={progressBarPosition}
createProgressBarSlot={(page, pageLoadStates, pagesIndex) => {
if (isHidden && isMinimized) {
return null;
}
return (
createProgressBarSlot={useCallback(
(
page,
pagesIndex,
primaryPageLoadState,
secondaryPageLoadState,
isCurrentPage,
isLeadingPage,
_,
totalPages_,
) => (
<ReaderProgressBarSlotDesktop
pageName={page.name}
pageUrl={page.primary.url}
primaryPageLoadState={pageLoadStates[page.primary.index].loaded}
secondaryPageLoadState={
page.secondary ? pageLoadStates[page.secondary.index].loaded : undefined
}
primaryPageLoadState={primaryPageLoadState}
secondaryPageLoadState={secondaryPageLoadState}
isHorizontal={isHorizontal}
isVertical={isVertical}
progressBarPosition={progressBarPosition}
isCurrentPage={currentPagesIndex === pagesIndex}
isCurrentPage={isCurrentPage}
isFirstPage={pagesIndex === 0}
isLastPage={pagesIndex === pages.length - 1}
isLeadingPage={pagesIndex < currentPagesIndex}
isLastPage={pagesIndex === totalPages_ - 1}
isLeadingPage={isLeadingPage}
isDragging={isDragging}
/>
);
}}
),
[isHorizontal, isVertical, isDragging, progressBarPosition],
)}
slotProps={{
container: {
sx: {