diff --git a/src/modules/downloads/screens/DownloadQueue.tsx b/src/modules/downloads/screens/DownloadQueue.tsx
index 6bed1361..5d97b771 100644
--- a/src/modules/downloads/screens/DownloadQueue.tsx
+++ b/src/modules/downloads/screens/DownloadQueue.tsx
@@ -16,7 +16,7 @@ import Stack from '@mui/material/Stack';
import Box, { BoxProps } from '@mui/material/Box';
import Tooltip from '@mui/material/Tooltip';
import IconButton from '@mui/material/IconButton';
-import React, { useContext, useEffect, useLayoutEffect } from 'react';
+import React, { memo, useCallback, useContext, useEffect, useLayoutEffect } from 'react';
import { DragDropContext, Draggable, DraggableProvided, DropResult } from 'react-beautiful-dnd';
import Typography from '@mui/material/Typography';
import { Link } from 'react-router-dom';
@@ -45,79 +45,86 @@ const HeightPreservingItem = ({ children, ...props }: BoxProps) => (
);
-const DownloadChapterItem = ({
- provided,
- item,
- handleDelete,
- handleRetry,
-}: {
- provided: DraggableProvided;
- item: ChapterDownloadStatus;
- handleDelete: (chapter: ChapterIdInfo) => void;
- handleRetry: (chapter: ChapterIdInfo) => void;
-}) => {
- const { t } = useTranslation();
+const DownloadChapterItem = memo(
+ ({
+ provided,
+ item,
+ handleDelete,
+ handleRetry,
+ }: {
+ provided: DraggableProvided;
+ item: ChapterDownloadStatus;
+ handleDelete: (chapter: ChapterIdInfo) => void;
+ handleRetry: (chapter: ChapterIdInfo) => void;
+ }) => {
+ const { t } = useTranslation();
- return (
-
-
-
-
-
-
-
-
-
- {item.manga.title}
-
-
- {item.chapter.name}
-
-
-
- {item.state === DownloadState.Error && (
-
+ return (
+
+
+
+
+
+
+
+
+
+ {item.manga.title}
+
+
+ {item.chapter.name}
+
+
+
+ {item.state === DownloadState.Error && (
+
+ {
+ e.preventDefault();
+ e.stopPropagation();
+ handleRetry(item.chapter);
+ }}
+ size="large"
+ >
+
+
+
+ )}
+
{
e.preventDefault();
e.stopPropagation();
- handleRetry(item.chapter);
+ handleDelete(item.chapter);
}}
size="large"
>
-
+
- )}
-
- {
- e.preventDefault();
- e.stopPropagation();
- handleDelete(item.chapter);
- }}
- size="large"
- >
-
-
-
-
-
-
-
- );
-};
+
+
+
+
+ );
+ },
+);
export const DownloadQueue: React.FC = () => {
const { t } = useTranslation();
@@ -213,15 +220,15 @@ export const DownloadQueue: React.FC = () => {
categoryReorder(queue, result.source.index, result.destination.index);
};
- const handleRetry = async (chapter: ChapterIdInfo) => {
+ const handleRetry = useCallback(async (chapter: ChapterIdInfo) => {
try {
await requestManager.addChapterToDownloadQueue(chapter.id).response;
} catch (e) {
makeToast(t('download.queue.error.label.failed_to_remove'), 'error', getErrorMessage(e));
}
- };
+ }, []);
- const handleDelete = async (chapter: ChapterIdInfo) => {
+ const handleDelete = useCallback(async (chapter: ChapterIdInfo) => {
const isRunning = status === DownloaderState.Started;
try {
@@ -246,7 +253,7 @@ export const DownloadQueue: React.FC = () => {
}
requestManager.startDownloads().response.catch(defaultPromiseErrorHandler('DownloadQueue::startDownloads'));
- };
+ }, []);
if (isLoading) {
return ;
@@ -285,17 +292,17 @@ export const DownloadQueue: React.FC = () => {
item.chapter.id}
- itemContent={(index, item) => (
-
+ totalCount={queue.length}
+ computeItemKey={(index) => queue[index].chapter.id}
+ itemContent={(index) => (
+
{(draggableProvided) => (