Skip to content

Commit f8e27b8

Browse files
fix(ui): memoize model manager components
1 parent 47414be commit f8e27b8

37 files changed

+192
-109
lines changed

invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/HuggingFaceFolder/HuggingFaceForm.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import { Button, Flex, FormControl, FormErrorMessage, FormHelperText, FormLabel, Input } from '@invoke-ai/ui-library';
22
import { useInstallModel } from 'features/modelManagerV2/hooks/useInstallModel';
33
import type { ChangeEventHandler } from 'react';
4-
import { useCallback, useState } from 'react';
4+
import { memo, useCallback, useState } from 'react';
55
import { useTranslation } from 'react-i18next';
66
import { useLazyGetHuggingFaceModelsQuery } from 'services/api/endpoints/models';
77

88
import { HuggingFaceResults } from './HuggingFaceResults';
99

10-
export const HuggingFaceForm = () => {
10+
export const HuggingFaceForm = memo(() => {
1111
const [huggingFaceRepo, setHuggingFaceRepo] = useState('');
1212
const [displayResults, setDisplayResults] = useState(false);
1313
const [errorMessage, setErrorMessage] = useState('');
@@ -66,4 +66,6 @@ export const HuggingFaceForm = () => {
6666
{data && data.urls && displayResults && <HuggingFaceResults results={data.urls} />}
6767
</Flex>
6868
);
69-
};
69+
});
70+
71+
HuggingFaceForm.displayName = 'HuggingFaceForm';

invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/HuggingFaceFolder/HuggingFaceResultItem.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import { Flex, IconButton, Text } from '@invoke-ai/ui-library';
22
import { useInstallModel } from 'features/modelManagerV2/hooks/useInstallModel';
3-
import { useCallback } from 'react';
3+
import { memo, useCallback } from 'react';
44
import { useTranslation } from 'react-i18next';
55
import { PiPlusBold } from 'react-icons/pi';
66

77
type Props = {
88
result: string;
99
};
10-
export const HuggingFaceResultItem = ({ result }: Props) => {
10+
export const HuggingFaceResultItem = memo(({ result }: Props) => {
1111
const { t } = useTranslation();
1212

1313
const [installModel] = useInstallModel();
@@ -27,4 +27,6 @@ export const HuggingFaceResultItem = ({ result }: Props) => {
2727
<IconButton aria-label={t('modelManager.install')} icon={<PiPlusBold />} onClick={onClick} size="sm" />
2828
</Flex>
2929
);
30-
};
30+
});
31+
32+
HuggingFaceResultItem.displayName = 'HuggingFaceResultItem';

invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/HuggingFaceFolder/HuggingFaceResults.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {
1111
import ScrollableContent from 'common/components/OverlayScrollbars/ScrollableContent';
1212
import { useInstallModel } from 'features/modelManagerV2/hooks/useInstallModel';
1313
import type { ChangeEventHandler } from 'react';
14-
import { useCallback, useMemo, useState } from 'react';
14+
import { memo, useCallback, useMemo, useState } from 'react';
1515
import { useTranslation } from 'react-i18next';
1616
import { PiXBold } from 'react-icons/pi';
1717

@@ -21,7 +21,7 @@ type HuggingFaceResultsProps = {
2121
results: string[];
2222
};
2323

24-
export const HuggingFaceResults = ({ results }: HuggingFaceResultsProps) => {
24+
export const HuggingFaceResults = memo(({ results }: HuggingFaceResultsProps) => {
2525
const { t } = useTranslation();
2626
const [searchTerm, setSearchTerm] = useState('');
2727

@@ -93,4 +93,6 @@ export const HuggingFaceResults = ({ results }: HuggingFaceResultsProps) => {
9393
</Flex>
9494
</>
9595
);
96-
};
96+
});
97+
98+
HuggingFaceResults.displayName = 'HuggingFaceResults';

invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/InstallModelForm.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Button, Checkbox, Flex, FormControl, FormHelperText, FormLabel, Input } from '@invoke-ai/ui-library';
22
import { useInstallModel } from 'features/modelManagerV2/hooks/useInstallModel';
33
import { t } from 'i18next';
4-
import { useCallback } from 'react';
4+
import { memo, useCallback } from 'react';
55
import type { SubmitHandler } from 'react-hook-form';
66
import { useForm } from 'react-hook-form';
77

@@ -10,7 +10,7 @@ type SimpleImportModelConfig = {
1010
inplace: boolean;
1111
};
1212

13-
export const InstallModelForm = () => {
13+
export const InstallModelForm = memo(() => {
1414
const [installModel, { isLoading }] = useInstallModel();
1515

1616
const { register, handleSubmit, formState, reset } = useForm<SimpleImportModelConfig>({
@@ -74,4 +74,6 @@ export const InstallModelForm = () => {
7474
</Flex>
7575
</form>
7676
);
77-
};
77+
});
78+
79+
InstallModelForm.displayName = 'InstallModelForm';

invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/ModelInstallQueue/ModelInstallQueue.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@ import { Box, Button, Flex, Heading } from '@invoke-ai/ui-library';
22
import ScrollableContent from 'common/components/OverlayScrollbars/ScrollableContent';
33
import { toast } from 'features/toast/toast';
44
import { t } from 'i18next';
5-
import { useCallback, useMemo } from 'react';
5+
import { memo, useCallback, useMemo } from 'react';
66
import { useListModelInstallsQuery, usePruneCompletedModelInstallsMutation } from 'services/api/endpoints/models';
77

88
import { ModelInstallQueueItem } from './ModelInstallQueueItem';
99

10-
export const ModelInstallQueue = () => {
10+
export const ModelInstallQueue = memo(() => {
1111
const { data } = useListModelInstallsQuery();
1212

1313
const [_pruneCompletedModelInstalls] = usePruneCompletedModelInstallsMutation();
@@ -61,4 +61,6 @@ export const ModelInstallQueue = () => {
6161
</Box>
6262
</Flex>
6363
);
64-
};
64+
});
65+
66+
ModelInstallQueue.displayName = 'ModelInstallQueue';

invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/ModelInstallQueue/ModelInstallQueueItem.tsx

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { Flex, IconButton, Progress, Text, Tooltip } from '@invoke-ai/ui-library
22
import { toast } from 'features/toast/toast';
33
import { t } from 'i18next';
44
import { isNil } from 'lodash-es';
5-
import { useCallback, useMemo } from 'react';
5+
import { memo, useCallback, useMemo } from 'react';
66
import { PiXBold } from 'react-icons/pi';
77
import { useCancelModelInstallMutation } from 'services/api/endpoints/models';
88
import type { ModelInstallJob } from 'services/api/types';
@@ -25,7 +25,7 @@ const formatBytes = (bytes: number) => {
2525
return `${bytes.toFixed(2)} ${units[i]}`;
2626
};
2727

28-
export const ModelInstallQueueItem = (props: ModelListItemProps) => {
28+
export const ModelInstallQueueItem = memo((props: ModelListItemProps) => {
2929
const { installJob } = props;
3030

3131
const [deleteImportModel] = useCancelModelInstallMutation();
@@ -124,15 +124,17 @@ export const ModelInstallQueueItem = (props: ModelListItemProps) => {
124124
/>
125125
</Flex>
126126
);
127-
};
127+
});
128+
129+
ModelInstallQueueItem.displayName = 'ModelInstallQueueItem';
128130

129131
type TooltipLabelProps = {
130132
installJob: ModelInstallJob;
131133
name: string;
132134
source: string;
133135
};
134136

135-
const TooltipLabel = ({ name, source, installJob }: TooltipLabelProps) => {
137+
const TooltipLabel = memo(({ name, source, installJob }: TooltipLabelProps) => {
136138
const progressString = useMemo(() => {
137139
if (installJob.status !== 'downloading' || installJob.bytes === undefined || installJob.total_bytes === undefined) {
138140
return '';
@@ -156,4 +158,6 @@ const TooltipLabel = ({ name, source, installJob }: TooltipLabelProps) => {
156158
)}
157159
</>
158160
);
159-
};
161+
});
162+
163+
TooltipLabel.displayName = 'TooltipLabel';

invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/ScanFolder/ScanFolderForm.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@ import { Button, Flex, FormControl, FormErrorMessage, FormHelperText, FormLabel,
22
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
33
import { setScanPath } from 'features/modelManagerV2/store/modelManagerV2Slice';
44
import type { ChangeEventHandler } from 'react';
5-
import { useCallback, useState } from 'react';
5+
import { memo, useCallback, useState } from 'react';
66
import { useTranslation } from 'react-i18next';
77
import { useLazyScanFolderQuery } from 'services/api/endpoints/models';
88

99
import { ScanModelsResults } from './ScanFolderResults';
1010

11-
export const ScanModelsForm = () => {
11+
export const ScanModelsForm = memo(() => {
1212
const scanPath = useAppSelector((state) => state.modelmanagerV2.scanPath);
1313
const dispatch = useAppDispatch();
1414
const [errorMessage, setErrorMessage] = useState('');
@@ -56,4 +56,6 @@ export const ScanModelsForm = () => {
5656
{data && <ScanModelsResults results={data} />}
5757
</Flex>
5858
);
59-
};
59+
});
60+
61+
ScanModelsForm.displayName = 'ScanModelsForm';

invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/ScanFolder/ScanFolderResultItem.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Badge, Box, Flex, IconButton, Text } from '@invoke-ai/ui-library';
2-
import { useCallback } from 'react';
2+
import { memo, useCallback } from 'react';
33
import { useTranslation } from 'react-i18next';
44
import { PiPlusBold } from 'react-icons/pi';
55
import type { ScanFolderResponse } from 'services/api/endpoints/models';
@@ -8,7 +8,7 @@ type Props = {
88
result: ScanFolderResponse[number];
99
installModel: (source: string) => void;
1010
};
11-
export const ScanModelResultItem = ({ result, installModel }: Props) => {
11+
export const ScanModelResultItem = memo(({ result, installModel }: Props) => {
1212
const { t } = useTranslation();
1313

1414
const handleInstall = useCallback(() => {
@@ -30,4 +30,6 @@ export const ScanModelResultItem = ({ result, installModel }: Props) => {
3030
</Box>
3131
</Flex>
3232
);
33-
};
33+
});
34+
35+
ScanModelResultItem.displayName = 'ScanModelResultItem';

invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/ScanFolder/ScanFolderResults.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import {
1414
import ScrollableContent from 'common/components/OverlayScrollbars/ScrollableContent';
1515
import { useInstallModel } from 'features/modelManagerV2/hooks/useInstallModel';
1616
import type { ChangeEvent, ChangeEventHandler } from 'react';
17-
import { useCallback, useMemo, useState } from 'react';
17+
import { memo, useCallback, useMemo, useState } from 'react';
1818
import { useTranslation } from 'react-i18next';
1919
import { PiXBold } from 'react-icons/pi';
2020
import type { ScanFolderResponse } from 'services/api/endpoints/models';
@@ -25,7 +25,7 @@ type ScanModelResultsProps = {
2525
results: ScanFolderResponse;
2626
};
2727

28-
export const ScanModelsResults = ({ results }: ScanModelResultsProps) => {
28+
export const ScanModelsResults = memo(({ results }: ScanModelResultsProps) => {
2929
const { t } = useTranslation();
3030
const [searchTerm, setSearchTerm] = useState('');
3131
const [inplace, setInplace] = useState(true);
@@ -116,4 +116,6 @@ export const ScanModelsResults = ({ results }: ScanModelResultsProps) => {
116116
</Flex>
117117
</>
118118
);
119-
};
119+
});
120+
121+
ScanModelsResults.displayName = 'ScanModelsResults';

invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/StarterModels/StartModelsResultItem.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
import { Badge, Box, Flex, IconButton, Text } from '@invoke-ai/ui-library';
22
import { useInstallModel } from 'features/modelManagerV2/hooks/useInstallModel';
33
import ModelBaseBadge from 'features/modelManagerV2/subpanels/ModelManagerPanel/ModelBaseBadge';
4-
import { useCallback, useMemo } from 'react';
4+
import { memo, useCallback, useMemo } from 'react';
55
import { useTranslation } from 'react-i18next';
66
import { PiPlusBold } from 'react-icons/pi';
77
import type { GetStarterModelsResponse } from 'services/api/endpoints/models';
88

99
type Props = {
1010
result: GetStarterModelsResponse[number];
1111
};
12-
export const StarterModelsResultItem = ({ result }: Props) => {
12+
export const StarterModelsResultItem = memo(({ result }: Props) => {
1313
const { t } = useTranslation();
1414
const allSources = useMemo(() => {
1515
const _allSources = [{ source: result.source, config: { name: result.name, description: result.description } }];
@@ -47,4 +47,6 @@ export const StarterModelsResultItem = ({ result }: Props) => {
4747
</Box>
4848
</Flex>
4949
);
50-
};
50+
});
51+
52+
StarterModelsResultItem.displayName = 'StarterModelsResultItem';

0 commit comments

Comments
 (0)