diff --git a/invokeai/frontend/web/src/app/components/App.tsx b/invokeai/frontend/web/src/app/components/App.tsx index 8c033440e3..b3ffeee333 100644 --- a/invokeai/frontend/web/src/app/components/App.tsx +++ b/invokeai/frontend/web/src/app/components/App.tsx @@ -36,7 +36,8 @@ const App = ({ config = DEFAULT_CONFIG, selectedImage }: Props) => { const logger = useLogger('system'); const dispatch = useAppDispatch(); - const { handlePreselectedImage } = usePreselectedImage(); + const { handleSendToCanvas, handleSendToImg2Img, handleUseAllMetadata } = + usePreselectedImage(selectedImage?.imageName); const handleReset = useCallback(() => { localStorage.clear(); location.reload(); @@ -59,8 +60,22 @@ const App = ({ config = DEFAULT_CONFIG, selectedImage }: Props) => { }, [dispatch]); useEffect(() => { - handlePreselectedImage(selectedImage); - }, [handlePreselectedImage, selectedImage]); + if (selectedImage && selectedImage.action === 'sendToCanvas') { + handleSendToCanvas(); + } + }, [selectedImage, handleSendToCanvas]); + + useEffect(() => { + if (selectedImage && selectedImage.action === 'sendToImg2Img') { + handleSendToImg2Img(); + } + }, [selectedImage, handleSendToImg2Img]); + + useEffect(() => { + if (selectedImage && selectedImage.action === 'useAllParameters') { + handleUseAllMetadata(); + } + }, [selectedImage, handleUseAllMetadata]); const headerComponent = useStore($headerComponent); diff --git a/invokeai/frontend/web/src/features/parameters/hooks/usePreselectedImage.ts b/invokeai/frontend/web/src/features/parameters/hooks/usePreselectedImage.ts index 62bdab616a..a14430a55d 100644 --- a/invokeai/frontend/web/src/features/parameters/hooks/usePreselectedImage.ts +++ b/invokeai/frontend/web/src/features/parameters/hooks/usePreselectedImage.ts @@ -1,7 +1,7 @@ import { skipToken } from '@reduxjs/toolkit/dist/query'; import { CoreMetadata } from 'features/nodes/types/types'; import { t } from 'i18next'; -import { useCallback, useState } from 'react'; +import { useCallback } from 'react'; import { useAppToaster } from '../../../app/components/Toaster'; import { useAppDispatch } from '../../../app/store/storeHooks'; import { @@ -13,70 +13,46 @@ import { setActiveTab } from '../../ui/store/uiSlice'; import { initialImageSelected } from '../store/actions'; import { useRecallParameters } from './useRecallParameters'; -type SelectedImage = { - imageName: string; - action: 'sendToImg2Img' | 'sendToCanvas' | 'useAllParameters'; -}; - -export const usePreselectedImage = () => { +export const usePreselectedImage = (imageName?: string) => { const dispatch = useAppDispatch(); - const [imageNameForDto, setImageNameForDto] = useState(); - const [imageNameForMetadata, setImageNameForMetadata] = useState< - string | undefined - >(); + const { recallAllParameters } = useRecallParameters(); const toaster = useAppToaster(); const { currentData: selectedImageDto } = useGetImageDTOQuery( - imageNameForDto ?? skipToken + imageName ?? skipToken ); const { currentData: selectedImageMetadata } = useGetImageMetadataQuery( - imageNameForMetadata ?? skipToken + imageName ?? skipToken ); - const handlePreselectedImage = useCallback( - (selectedImage?: SelectedImage) => { - if (!selectedImage) { - return; - } + const handleSendToCanvas = useCallback(() => { + if (selectedImageDto) { + dispatch(setInitialCanvasImage(selectedImageDto)); + dispatch(setActiveTab('unifiedCanvas')); + toaster({ + title: t('toast.sentToUnifiedCanvas'), + status: 'info', + duration: 2500, + isClosable: true, + }); + } + }, [dispatch, toaster, selectedImageDto]); - if (selectedImage.action === 'sendToCanvas') { - setImageNameForDto(selectedImage?.imageName); - if (selectedImageDto) { - dispatch(setInitialCanvasImage(selectedImageDto)); - dispatch(setActiveTab('unifiedCanvas')); - toaster({ - title: t('toast.sentToUnifiedCanvas'), - status: 'info', - duration: 2500, - isClosable: true, - }); - } - } + const handleSendToImg2Img = useCallback(() => { + if (selectedImageDto) { + dispatch(initialImageSelected(selectedImageDto)); + } + }, [dispatch, selectedImageDto]); - if (selectedImage.action === 'sendToImg2Img') { - setImageNameForDto(selectedImage?.imageName); - if (selectedImageDto) { - dispatch(initialImageSelected(selectedImageDto)); - } - } + const handleUseAllMetadata = useCallback(() => { + if (selectedImageMetadata) { + recallAllParameters(selectedImageMetadata.metadata as CoreMetadata); + } + // disabled because `recallAllParameters` changes the model, but its dep to prepare LoRAs has model as a dep. this introduces circular logic that causes infinite re-renders + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [selectedImageMetadata]); - if (selectedImage.action === 'useAllParameters') { - setImageNameForMetadata(selectedImage?.imageName); - if (selectedImageMetadata) { - recallAllParameters(selectedImageMetadata.metadata as CoreMetadata); - } - } - }, - [ - dispatch, - selectedImageDto, - selectedImageMetadata, - recallAllParameters, - toaster, - ] - ); - - return { handlePreselectedImage }; + return { handleSendToCanvas, handleSendToImg2Img, handleUseAllMetadata }; };