From e32ade3b543719e82350b7bc8bb12f08f5f2f7d1 Mon Sep 17 00:00:00 2001 From: jeffvli Date: Fri, 9 Dec 2022 15:58:30 -0800 Subject: [PATCH] Improve virtual grid performance --- .../virtual-grid/grid-card/default-card.tsx | 15 ++-- .../grid-card/grid-card-controls.tsx | 24 ++++--- .../virtual-grid/grid-card/index.tsx | 40 +++++------ .../virtual-grid/grid-card/poster-card.tsx | 18 ++--- .../virtual-grid/virtual-grid-wrapper.tsx | 72 +++++++++++-------- .../virtual-grid/virtual-infinite-grid.tsx | 3 +- 6 files changed, 91 insertions(+), 81 deletions(-) diff --git a/packages/renderer/src/components/virtual-grid/grid-card/default-card.tsx b/packages/renderer/src/components/virtual-grid/grid-card/default-card.tsx index 5b5b9daec..075be4157 100644 --- a/packages/renderer/src/components/virtual-grid/grid-card/default-card.tsx +++ b/packages/renderer/src/components/virtual-grid/grid-card/default-card.tsx @@ -7,7 +7,7 @@ import { SimpleImg } from 'react-simple-img'; import type { ListChildComponentProps } from 'react-window'; import styled from 'styled-components'; import { Text } from '/@/components/text'; -import type { PlayQueueAddOptions, LibraryItem, CardRow, CardRoute, Play } from '/@/types'; +import type { LibraryItem, CardRow, CardRoute, Play } from '/@/types'; import GridCardControls from './grid-card-controls'; const CardWrapper = styled.div<{ @@ -113,7 +113,6 @@ interface BaseGridCardProps { controls: { cardControls: any[]; cardRows: CardRow[]; - handlePlayQueueAdd: (options: PlayQueueAddOptions) => void; itemType: LibraryItem; playButtonBehavior: Play; route: CardRoute; @@ -135,7 +134,7 @@ export const DefaultCard = ({ sizes, }: BaseGridCardProps) => { const navigate = useNavigate(); - const { index, isScrolling } = listChildProps; + const { index } = listChildProps; const { itemGap, itemHeight, itemWidth } = sizes; const { itemType, cardRows, route } = controls; @@ -190,12 +189,10 @@ export const DefaultCard = ({ )} - {!isScrolling && ( - - )} + diff --git a/packages/renderer/src/components/virtual-grid/grid-card/grid-card-controls.tsx b/packages/renderer/src/components/virtual-grid/grid-card/grid-card-controls.tsx index fca1e235f..5ffa2f992 100644 --- a/packages/renderer/src/components/virtual-grid/grid-card/grid-card-controls.tsx +++ b/packages/renderer/src/components/virtual-grid/grid-card/grid-card-controls.tsx @@ -42,9 +42,18 @@ const PlayButton = styled.button` `; const SecondaryButton = styled(_Button)` - fill: white !important; - svg: { - fill: white !important; + opacity: 0.8; + transition: opacity 0.2s ease-in-out; + transition: scale 0.2s linear; + + &:hover { + opacity: 1; + scale: 1.1; + } + + &:active { + opacity: 1; + scale: 1; } `; @@ -132,13 +141,7 @@ export const GridCardControls = ({ {/* */} {/* */} - + @@ -166,6 +169,7 @@ export const GridCardControls = ({ { e.preventDefault(); diff --git a/packages/renderer/src/components/virtual-grid/grid-card/index.tsx b/packages/renderer/src/components/virtual-grid/grid-card/index.tsx index 6f022aa23..6b9729f0e 100644 --- a/packages/renderer/src/components/virtual-grid/grid-card/index.tsx +++ b/packages/renderer/src/components/virtual-grid/grid-card/index.tsx @@ -1,11 +1,12 @@ -import { useMemo } from 'react'; +import { memo } from 'react'; import type { ListChildComponentProps } from 'react-window'; +import { areEqual } from 'react-window'; import { DefaultCard } from '/@/components/virtual-grid/grid-card/default-card'; import { PosterCard } from '/@/components/virtual-grid/grid-card/poster-card'; import type { GridCardData } from '/@/types'; import { CardDisplayType } from '/@/types'; -export const GridCard = ({ data, index, style, isScrolling }: ListChildComponentProps) => { +export const GridCard = memo(({ data, index, style }: ListChildComponentProps) => { const { itemHeight, itemWidth, @@ -13,7 +14,6 @@ export const GridCard = ({ data, index, style, isScrolling }: ListChildComponent itemGap, itemCount, cardControls, - handlePlayQueueAdd, cardRows, itemData, itemType, @@ -22,11 +22,8 @@ export const GridCard = ({ data, index, style, isScrolling }: ListChildComponent display, } = data as GridCardData; const cards = []; - const startIndex = useMemo(() => index * columnCount, [columnCount, index]); - const stopIndex = useMemo( - () => Math.min(itemCount - 1, startIndex + columnCount - 1), - [columnCount, itemCount, startIndex], - ); + const startIndex = index * columnCount; + const stopIndex = Math.min(itemCount - 1, startIndex + columnCount - 1); const View = display === CardDisplayType.CARD ? DefaultCard : PosterCard; @@ -38,28 +35,29 @@ export const GridCard = ({ data, index, style, isScrolling }: ListChildComponent controls={{ cardControls, cardRows, - handlePlayQueueAdd, itemType, playButtonBehavior, route, }} data={itemData[i]} - listChildProps={{ index, isScrolling }} + listChildProps={{ index }} sizes={{ itemGap, itemHeight, itemWidth }} />, ); } return ( -
- {cards} -
+ <> +
+ {cards} +
+ ); -}; +}, areEqual); diff --git a/packages/renderer/src/components/virtual-grid/grid-card/poster-card.tsx b/packages/renderer/src/components/virtual-grid/grid-card/poster-card.tsx index d4e934e0f..001d20047 100644 --- a/packages/renderer/src/components/virtual-grid/grid-card/poster-card.tsx +++ b/packages/renderer/src/components/virtual-grid/grid-card/poster-card.tsx @@ -8,7 +8,7 @@ import type { ListChildComponentProps } from 'react-window'; import styled from 'styled-components'; import { Skeleton } from '/@/components/skeleton'; import { Text } from '/@/components/text'; -import type { PlayQueueAddOptions, LibraryItem, CardRow, CardRoute, Play } from '/@/types'; +import type { LibraryItem, CardRow, CardRoute, Play } from '/@/types'; import GridCardControls from './grid-card-controls'; const CardWrapper = styled.div<{ @@ -117,7 +117,6 @@ interface BaseGridCardProps { columnIndex: number; controls: { cardRows: CardRow[]; - handlePlayQueueAdd: (options: PlayQueueAddOptions) => void; itemType: LibraryItem; playButtonBehavior: Play; route: CardRoute; @@ -166,7 +165,6 @@ export const PosterCard = ({ height={sizes.itemWidth} importance="auto" placeholder={'var(--card-default-bg)'} - // placeholder={data?.imagePlaceholderUrl || 'var(--card-default-bg)'} src={data?.imageUrl} width={sizes.itemWidth} /> @@ -184,14 +182,12 @@ export const PosterCard = ({ /> )} - {!listChildProps.isScrolling && ( - - - - )} + + + diff --git a/packages/renderer/src/components/virtual-grid/virtual-grid-wrapper.tsx b/packages/renderer/src/components/virtual-grid/virtual-grid-wrapper.tsx index 138c87554..a6fc4bd1a 100644 --- a/packages/renderer/src/components/virtual-grid/virtual-grid-wrapper.tsx +++ b/packages/renderer/src/components/virtual-grid/virtual-grid-wrapper.tsx @@ -1,11 +1,40 @@ import type { Ref } from 'react'; -import { useMemo } from 'react'; +import debounce from 'lodash/debounce'; +import memoize from 'memoize-one'; import type { FixedSizeListProps } from 'react-window'; import { FixedSizeList } from 'react-window'; import styled from 'styled-components'; import { GridCard } from '/@/components/virtual-grid/grid-card'; import type { CardRow, LibraryItem, CardDisplayType, CardRoute } from '/@/types'; +const createItemData = memoize( + ( + cardRows, + columnCount, + display, + itemCount, + itemData, + itemGap, + itemHeight, + itemType, + itemWidth, + route, + ) => ({ + cardRows, + columnCount, + display, + itemCount, + itemData, + itemGap, + itemHeight, + itemType, + itemWidth, + route, + }), +); + +const createScrollHandler = memoize((onScroll) => debounce(onScroll, 250)); + export const VirtualGridWrapper = ({ refInstance, cardRows, @@ -35,44 +64,31 @@ export const VirtualGridWrapper = ({ route?: CardRoute; rowCount: number; }) => { - const memoizedItemData = useMemo( - () => ({ - cardRows, - columnCount, - display, - itemCount, - itemData, - itemGap, - itemHeight, - itemType, - itemWidth, - route, - }), - [ - cardRows, - itemType, - columnCount, - itemCount, - itemData, - display, - itemGap, - itemHeight, - route, - itemWidth, - ], + const memoizedItemData = createItemData( + cardRows, + columnCount, + display, + itemCount, + itemData, + itemGap, + itemHeight, + itemType, + itemWidth, + route, ); + const memoizedOnScroll = createScrollHandler(onScroll); + return ( {GridCard} diff --git a/packages/renderer/src/components/virtual-grid/virtual-infinite-grid.tsx b/packages/renderer/src/components/virtual-grid/virtual-infinite-grid.tsx index 7a3f2e5a7..56524ae2c 100644 --- a/packages/renderer/src/components/virtual-grid/virtual-infinite-grid.tsx +++ b/packages/renderer/src/components/virtual-grid/virtual-infinite-grid.tsx @@ -86,7 +86,7 @@ export const VirtualInfiniteGrid = ({ [columnCount, fetchFn, itemData], ); - const debouncedLoadMoreItems = debounce(loadMoreItems, 400); + const debouncedLoadMoreItems = debounce(loadMoreItems, 500); useEffect(() => { if (loader.current) { @@ -110,7 +110,6 @@ export const VirtualInfiniteGrid = ({ > {({ onItemsRendered, ref: infiniteLoaderRef }) => (