Properly set virtuoso item keys
This commit is contained in:
@@ -259,6 +259,7 @@ export const ChapterList = ({
|
||||
}}
|
||||
components={{ Footer: () => <Box sx={{ paddingBottom: DEFAULT_FULL_FAB_HEIGHT }} /> }}
|
||||
totalCount={visibleChapters.length}
|
||||
computeItemKey={(index) => visibleChapters[index].id}
|
||||
itemContent={(index: number) => (
|
||||
<ChapterCard
|
||||
{...chaptersWithMeta[index]}
|
||||
|
||||
@@ -287,12 +287,9 @@ export const DownloadQueue: React.FC = () => {
|
||||
components={{
|
||||
Item: HeightPreservingItem,
|
||||
}}
|
||||
computeItemKey={(_, item) => item.manga.id}
|
||||
itemContent={(index, item) => (
|
||||
<Draggable
|
||||
key={`${item.manga.id}-${item.chapter.sourceOrder}`}
|
||||
draggableId={`${item.manga.id}-${item.chapter.sourceOrder}`}
|
||||
index={index}
|
||||
>
|
||||
<Draggable draggableId={`${item.manga.id}-${item.chapter.sourceOrder}`} index={index}>
|
||||
{(draggableProvided) => (
|
||||
<DownloadChapterItem
|
||||
provided={draggableProvided}
|
||||
|
||||
@@ -39,6 +39,7 @@ import { StyledGroupHeader } from '@/modules/core/components/virtuoso/StyledGrou
|
||||
import { StyledGroupItemWrapper } from '@/modules/core/components/virtuoso/StyledGroupItemWrapper.tsx';
|
||||
import { EmptyViewAbsoluteCentered } from '@/modules/core/components/placeholder/EmptyViewAbsoluteCentered.tsx';
|
||||
import { defaultPromiseErrorHandler } from '@/lib/DefaultPromiseErrorHandler.ts';
|
||||
import { VirtuosoUtil } from '@/lib/virtuoso/Virtuoso.util.tsx';
|
||||
|
||||
const LANGUAGE = 0;
|
||||
const EXTENSIONS = 1;
|
||||
@@ -160,6 +161,12 @@ export function Extensions({ tabsMenuHeight }: { tabsMenuHeight: number }) {
|
||||
[filteredGroupedExtensions],
|
||||
);
|
||||
|
||||
const computeItemKey = VirtuosoUtil.useCreateGroupedComputeItemKey(
|
||||
groupCounts,
|
||||
useCallback((index) => filteredGroupedExtensions[index][0], [filteredGroupedExtensions]),
|
||||
useCallback((index) => visibleExtensions[index].pkgName, [visibleExtensions]),
|
||||
);
|
||||
|
||||
const submitExternalExtension = (file: File) => {
|
||||
if (file.name.toLowerCase().endsWith('apk')) {
|
||||
if (inputRef.current) {
|
||||
@@ -298,13 +305,12 @@ export function Extensions({ tabsMenuHeight }: { tabsMenuHeight: number }) {
|
||||
</StyledGroupHeader>
|
||||
);
|
||||
}}
|
||||
computeItemKey={computeItemKey}
|
||||
itemContent={(index) => {
|
||||
const item = visibleExtensions[index];
|
||||
|
||||
return (
|
||||
<StyledGroupItemWrapper
|
||||
key={`${item.pkgName}_${item.isInstalled}_${item.isObsolete}_${item.hasUpdate}`}
|
||||
>
|
||||
<StyledGroupItemWrapper>
|
||||
<ExtensionCard
|
||||
extension={item}
|
||||
handleUpdate={handleExtensionUpdate}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
*/
|
||||
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useContext, useLayoutEffect, useMemo } from 'react';
|
||||
import { useCallback, useContext, useLayoutEffect, useMemo } from 'react';
|
||||
import IconButton from '@mui/material/IconButton';
|
||||
import SettingsIcon from '@mui/icons-material/Settings';
|
||||
import PopupState, { bindMenu, bindTrigger } from 'material-ui-popup-state';
|
||||
@@ -36,6 +36,7 @@ import { BaseMangaGrid } from '@/modules/manga/components/BaseMangaGrid.tsx';
|
||||
import { IMangaGridProps } from '@/modules/manga/components/MangaGrid.tsx';
|
||||
import { StyledGroupItemWrapper } from '@/modules/core/components/virtuoso/StyledGroupItemWrapper.tsx';
|
||||
import { enhancedCleanup } from '@/util/Strings.ts';
|
||||
import { VirtuosoUtil } from '@/lib/virtuoso/Virtuoso.util.tsx';
|
||||
|
||||
const findDuplicatesByTitle = <Manga extends Pick<MangaType, 'title'>>(
|
||||
libraryMangas: Manga[],
|
||||
@@ -180,6 +181,15 @@ export const LibraryDuplicates = () => {
|
||||
[mangasByTitle],
|
||||
);
|
||||
|
||||
const computeItemKey = VirtuosoUtil.useCreateGroupedComputeItemKey(
|
||||
mangasCountByTitle,
|
||||
useCallback((index) => duplicatedTitles[index], [duplicatedTitles]),
|
||||
useCallback(
|
||||
(index, groupIndex) => `${duplicatedTitles[groupIndex]}-${duplicatedMangas[index].id}}`,
|
||||
[duplicatedTitles, duplicatedMangas],
|
||||
),
|
||||
);
|
||||
|
||||
if (loading) {
|
||||
return <LoadingPlaceholder />;
|
||||
}
|
||||
@@ -203,8 +213,9 @@ export const LibraryDuplicates = () => {
|
||||
{duplicatedTitles[index]}
|
||||
</StyledGroupHeader>
|
||||
)}
|
||||
computeItemKey={computeItemKey}
|
||||
itemContent={(index) => (
|
||||
<StyledGroupItemWrapper key={duplicatedMangas[index].id}>
|
||||
<StyledGroupItemWrapper>
|
||||
<MangaCard
|
||||
manga={duplicatedMangas[index] as IMangaGridProps['mangas'][number]}
|
||||
gridLayout={gridLayout}
|
||||
|
||||
@@ -69,7 +69,6 @@ const createMangaCard = (
|
||||
mode?: MangaCardProps['mode'],
|
||||
) => (
|
||||
<MangaCard
|
||||
key={manga.id}
|
||||
manga={manga}
|
||||
gridLayout={gridLayout}
|
||||
inLibraryIndicator={inLibraryIndicator}
|
||||
@@ -195,6 +194,7 @@ const VerticalGrid = forwardRef(
|
||||
restoreStateFrom={snapshot}
|
||||
stateChanged={persistGridState}
|
||||
endReached={() => loadMore()}
|
||||
computeItemKey={(index) => mangas[index].id}
|
||||
itemContent={(index) =>
|
||||
createMangaCard(
|
||||
mangas[index],
|
||||
|
||||
@@ -36,6 +36,7 @@ import { defaultPromiseErrorHandler } from '@/lib/DefaultPromiseErrorHandler.ts'
|
||||
import { TypographyMaxLines } from '@/modules/core/components/TypographyMaxLines.tsx';
|
||||
import { ChapterIdInfo, ChapterMangaInfo } from '@/modules/chapter/services/Chapters.ts';
|
||||
import { makeToast } from '@/modules/core/utils/Toast.ts';
|
||||
import { VirtuosoUtil } from '@/lib/virtuoso/Virtuoso.util.tsx';
|
||||
|
||||
const groupByDate = (updates: Pick<ChapterType, 'fetchedAt'>[]): [date: string, items: number][] => {
|
||||
if (!updates.length) {
|
||||
@@ -74,6 +75,12 @@ export const Updates: React.FC = () => {
|
||||
const { data: downloaderData } = requestManager.useGetDownloadStatus();
|
||||
const queue = downloaderData?.downloadStatus.queue ?? [];
|
||||
|
||||
const computeItemKey = VirtuosoUtil.useCreateGroupedComputeItemKey(
|
||||
groupCounts,
|
||||
useCallback((index) => groupedUpdates[index][0], [groupedUpdates]),
|
||||
useCallback((index) => updateEntries[index].id, [updateEntries]),
|
||||
);
|
||||
|
||||
const lastUpdateTimestampCompRef = useRef<HTMLElement>(null);
|
||||
const [lastUpdateTimestampCompHeight, setLastUpdateTimestampCompHeight] = useState(0);
|
||||
useLayoutEffect(() => {
|
||||
@@ -169,13 +176,14 @@ export const Updates: React.FC = () => {
|
||||
{groupedUpdates[index][0]}
|
||||
</StyledGroupHeader>
|
||||
)}
|
||||
computeItemKey={computeItemKey}
|
||||
itemContent={(index) => {
|
||||
const chapter = updateEntries[index];
|
||||
const { manga } = chapter;
|
||||
const download = downloadForChapter(chapter);
|
||||
|
||||
return (
|
||||
<StyledGroupItemWrapper key={index}>
|
||||
<StyledGroupItemWrapper>
|
||||
<Card>
|
||||
<CardActionArea
|
||||
component={Link}
|
||||
|
||||
Reference in New Issue
Block a user