Skip to content

Commit 8158124

Browse files
fix(ui): usePreselectedImage causing re-renders
This hook was rerendering any time anything changed. Moved it to a logical component, put its useEffects inside the component. This reduces the effect of the rerenders to just that tiny always-null component.
1 parent 5d31df0 commit 8158124

File tree

3 files changed

+46
-27
lines changed

3 files changed

+46
-27
lines changed

invokeai/frontend/web/src/app/components/App.tsx

Lines changed: 5 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import { Flex, Grid } from '@chakra-ui/react';
2+
import { useStore } from '@nanostores/react';
23
import { useLogger } from 'app/logging/useLogger';
34
import { appStarted } from 'app/store/middleware/listenerMiddleware/listeners/appStarted';
5+
import { $headerComponent } from 'app/store/nanostores/headerComponent';
46
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
57
import { PartialAppConfig } from 'app/types/invokeai';
68
import ImageUploader from 'common/components/ImageUploader';
@@ -14,12 +16,10 @@ import i18n from 'i18n';
1416
import { size } from 'lodash-es';
1517
import { memo, useCallback, useEffect } from 'react';
1618
import { ErrorBoundary } from 'react-error-boundary';
17-
import { usePreselectedImage } from '../../features/parameters/hooks/usePreselectedImage';
1819
import AppErrorBoundaryFallback from './AppErrorBoundaryFallback';
1920
import GlobalHotkeys from './GlobalHotkeys';
21+
import PreselectedImage from './PreselectedImage';
2022
import Toaster from './Toaster';
21-
import { useStore } from '@nanostores/react';
22-
import { $headerComponent } from 'app/store/nanostores/headerComponent';
2323

2424
const DEFAULT_CONFIG = {};
2525

@@ -36,8 +36,7 @@ const App = ({ config = DEFAULT_CONFIG, selectedImage }: Props) => {
3636

3737
const logger = useLogger('system');
3838
const dispatch = useAppDispatch();
39-
const { handleSendToCanvas, handleSendToImg2Img, handleUseAllMetadata } =
40-
usePreselectedImage(selectedImage?.imageName);
39+
4140
const handleReset = useCallback(() => {
4241
localStorage.clear();
4342
location.reload();
@@ -59,24 +58,6 @@ const App = ({ config = DEFAULT_CONFIG, selectedImage }: Props) => {
5958
dispatch(appStarted());
6059
}, [dispatch]);
6160

62-
useEffect(() => {
63-
if (selectedImage && selectedImage.action === 'sendToCanvas') {
64-
handleSendToCanvas();
65-
}
66-
}, [selectedImage, handleSendToCanvas]);
67-
68-
useEffect(() => {
69-
if (selectedImage && selectedImage.action === 'sendToImg2Img') {
70-
handleSendToImg2Img();
71-
}
72-
}, [selectedImage, handleSendToImg2Img]);
73-
74-
useEffect(() => {
75-
if (selectedImage && selectedImage.action === 'useAllParameters') {
76-
handleUseAllMetadata();
77-
}
78-
}, [selectedImage, handleUseAllMetadata]);
79-
8061
const headerComponent = useStore($headerComponent);
8162

8263
return (
@@ -112,6 +93,7 @@ const App = ({ config = DEFAULT_CONFIG, selectedImage }: Props) => {
11293
<ChangeBoardModal />
11394
<Toaster />
11495
<GlobalHotkeys />
96+
<PreselectedImage selectedImage={selectedImage} />
11597
</ErrorBoundary>
11698
);
11799
};
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { usePreselectedImage } from 'features/parameters/hooks/usePreselectedImage';
2+
import { memo } from 'react';
3+
4+
type Props = {
5+
selectedImage?: {
6+
imageName: string;
7+
action: 'sendToImg2Img' | 'sendToCanvas' | 'useAllParameters';
8+
};
9+
};
10+
11+
const PreselectedImage = (props: Props) => {
12+
usePreselectedImage(props.selectedImage);
13+
return null;
14+
};
15+
16+
export default memo(PreselectedImage);

invokeai/frontend/web/src/features/parameters/hooks/usePreselectedImage.ts

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { skipToken } from '@reduxjs/toolkit/dist/query';
22
import { CoreMetadata } from 'features/nodes/types/types';
33
import { t } from 'i18next';
4-
import { useCallback } from 'react';
4+
import { useCallback, useEffect } from 'react';
55
import { useAppToaster } from '../../../app/components/Toaster';
66
import { useAppDispatch } from '../../../app/store/storeHooks';
77
import {
@@ -13,18 +13,21 @@ import { setActiveTab } from '../../ui/store/uiSlice';
1313
import { initialImageSelected } from '../store/actions';
1414
import { useRecallParameters } from './useRecallParameters';
1515

16-
export const usePreselectedImage = (imageName?: string) => {
16+
export const usePreselectedImage = (selectedImage?: {
17+
imageName: string;
18+
action: 'sendToImg2Img' | 'sendToCanvas' | 'useAllParameters';
19+
}) => {
1720
const dispatch = useAppDispatch();
1821

1922
const { recallAllParameters } = useRecallParameters();
2023
const toaster = useAppToaster();
2124

2225
const { currentData: selectedImageDto } = useGetImageDTOQuery(
23-
imageName ?? skipToken
26+
selectedImage?.imageName ?? skipToken
2427
);
2528

2629
const { currentData: selectedImageMetadata } = useGetImageMetadataQuery(
27-
imageName ?? skipToken
30+
selectedImage?.imageName ?? skipToken
2831
);
2932

3033
const handleSendToCanvas = useCallback(() => {
@@ -54,5 +57,23 @@ export const usePreselectedImage = (imageName?: string) => {
5457
// eslint-disable-next-line react-hooks/exhaustive-deps
5558
}, [selectedImageMetadata]);
5659

60+
useEffect(() => {
61+
if (selectedImage && selectedImage.action === 'sendToCanvas') {
62+
handleSendToCanvas();
63+
}
64+
}, [selectedImage, handleSendToCanvas]);
65+
66+
useEffect(() => {
67+
if (selectedImage && selectedImage.action === 'sendToImg2Img') {
68+
handleSendToImg2Img();
69+
}
70+
}, [selectedImage, handleSendToImg2Img]);
71+
72+
useEffect(() => {
73+
if (selectedImage && selectedImage.action === 'useAllParameters') {
74+
handleUseAllMetadata();
75+
}
76+
}, [selectedImage, handleUseAllMetadata]);
77+
5778
return { handleSendToCanvas, handleSendToImg2Img, handleUseAllMetadata };
5879
};

0 commit comments

Comments
 (0)