mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
fix(ui): fix excessive re-renders
This commit is contained in:
parent
9508e0c9db
commit
6b8ce34eb3
@ -4,7 +4,6 @@ import { isEqual } from 'lodash-es';
|
||||
import {
|
||||
ButtonGroup,
|
||||
Flex,
|
||||
FlexProps,
|
||||
Menu,
|
||||
MenuButton,
|
||||
MenuList,
|
||||
@ -82,9 +81,7 @@ const currentImageButtonsSelector = createSelector(
|
||||
}
|
||||
);
|
||||
|
||||
type CurrentImageButtonsProps = FlexProps;
|
||||
|
||||
const CurrentImageButtons = (props: CurrentImageButtonsProps) => {
|
||||
const CurrentImageButtons = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const {
|
||||
isConnected,
|
||||
@ -248,10 +245,9 @@ const CurrentImageButtons = (props: CurrentImageButtonsProps) => {
|
||||
alignItems: 'center',
|
||||
gap: 2,
|
||||
}}
|
||||
{...props}
|
||||
>
|
||||
<ButtonGroup isAttached={true} isDisabled={shouldDisableToolbarButtons}>
|
||||
<Menu>
|
||||
<Menu isLazy>
|
||||
<MenuButton
|
||||
as={IAIIconButton}
|
||||
aria-label={t('parameters.imageActions')}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { ButtonGroup, Divider, Flex } from '@chakra-ui/react';
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { stateSelector } from 'app/store/store';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||
import IAIButton from 'common/components/IAIButton';
|
||||
import IAICollapse from 'common/components/IAICollapse';
|
||||
@ -17,37 +17,36 @@ import {
|
||||
import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus';
|
||||
import { Fragment, memo } from 'react';
|
||||
import { FaPlus } from 'react-icons/fa';
|
||||
import { useGetControlNetModelsQuery } from 'services/api/endpoints/models';
|
||||
|
||||
const selector = createSelector(
|
||||
[stateSelector],
|
||||
({ controlAdapters }) => {
|
||||
const activeLabel: string[] = [];
|
||||
|
||||
const validIPAdapters = selectAllIPAdapters(controlAdapters);
|
||||
const validIPAdapterCount = validIPAdapters.length;
|
||||
if (validIPAdapterCount > 0) {
|
||||
activeLabel.push(`${validIPAdapterCount} IP`);
|
||||
const ipAdapters = selectAllIPAdapters(controlAdapters);
|
||||
const ipAdapterCount = ipAdapters.length;
|
||||
if (ipAdapterCount > 0) {
|
||||
activeLabel.push(`${ipAdapterCount} IP`);
|
||||
}
|
||||
|
||||
const validControlNets = selectAllControlNets(controlAdapters);
|
||||
const validControlNetCount = validControlNets.length;
|
||||
if (validControlNetCount > 0) {
|
||||
activeLabel.push(`${validControlNetCount} ControlNet`);
|
||||
const controlNets = selectAllControlNets(controlAdapters);
|
||||
const controlNetCount = controlNets.length;
|
||||
if (controlNetCount > 0) {
|
||||
activeLabel.push(`${controlNetCount} ControlNet`);
|
||||
}
|
||||
|
||||
const validT2IAdapters = selectAllT2IAdapters(controlAdapters);
|
||||
const validT2IAdapterCount = validT2IAdapters.length;
|
||||
if (validT2IAdapterCount > 0) {
|
||||
activeLabel.push(`${validT2IAdapterCount} T2I`);
|
||||
const t2iAdapters = selectAllT2IAdapters(controlAdapters);
|
||||
const t2iAdapterCount = t2iAdapters.length;
|
||||
if (t2iAdapterCount > 0) {
|
||||
activeLabel.push(`${t2iAdapterCount} T2I`);
|
||||
}
|
||||
|
||||
const controlAdapterIds = [ipAdapters, controlNets, t2iAdapters]
|
||||
.flat()
|
||||
.map((ca) => ca.id);
|
||||
|
||||
return {
|
||||
controlAdapters: [
|
||||
...validIPAdapters,
|
||||
...validControlNets,
|
||||
...validT2IAdapters,
|
||||
],
|
||||
controlAdapterIds,
|
||||
activeLabel: activeLabel.join(', '),
|
||||
};
|
||||
},
|
||||
@ -55,14 +54,16 @@ const selector = createSelector(
|
||||
);
|
||||
|
||||
const ParamControlNetCollapse = () => {
|
||||
const { controlAdapters, activeLabel } = useAppSelector(selector);
|
||||
const { controlAdapterIds, activeLabel } = useAppSelector(selector);
|
||||
const isControlNetDisabled = useFeatureStatus('controlNet').isFeatureDisabled;
|
||||
const dispatch = useAppDispatch();
|
||||
const { data: controlnetModels } = useGetControlNetModelsQuery();
|
||||
const { addControlNet } = useAddControlNet();
|
||||
const { addIPAdapter } = useAddIPAdapter();
|
||||
const { addT2IAdapter } = useAddT2IAdapter();
|
||||
|
||||
if (isControlNetDisabled) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<IAICollapse label="Control Adapters" activeLabel={activeLabel}>
|
||||
<Flex sx={{ flexDir: 'column', gap: 2 }}>
|
||||
@ -89,10 +90,10 @@ const ParamControlNetCollapse = () => {
|
||||
T2I Adapter
|
||||
</IAIButton>
|
||||
</ButtonGroup>
|
||||
{controlAdapters.map((ca, i) => (
|
||||
<Fragment key={ca.id}>
|
||||
{controlAdapterIds.map((id, i) => (
|
||||
<Fragment key={id}>
|
||||
{i > 0 && <Divider />}
|
||||
<ControlNet id={ca.id} />
|
||||
<ControlNet id={id} />
|
||||
</Fragment>
|
||||
))}
|
||||
</Flex>
|
||||
|
@ -2,11 +2,16 @@ import { createSelector } from '@reduxjs/toolkit';
|
||||
import { useAppToaster } from 'app/components/Toaster';
|
||||
import { stateSelector } from 'app/store/store';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||
import {
|
||||
CONTROLNET_MODEL_DEFAULT_PROCESSORS,
|
||||
CONTROLNET_PROCESSORS,
|
||||
} from 'features/controlNet/store/constants';
|
||||
import {
|
||||
CoreMetadata,
|
||||
LoRAMetadataItem,
|
||||
ControlNetMetadataItem,
|
||||
CoreMetadata,
|
||||
IPAdapterMetadataItem,
|
||||
LoRAMetadataItem,
|
||||
} from 'features/nodes/types/types';
|
||||
import {
|
||||
refinerModelChanged,
|
||||
@ -22,12 +27,13 @@ import {
|
||||
import { useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { ImageDTO } from 'services/api/types';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import {
|
||||
controlNetModelsAdapter,
|
||||
ipAdapterModelsAdapter,
|
||||
useGetIPAdapterModelsQuery,
|
||||
loraModelsAdapter,
|
||||
useGetControlNetModelsQuery,
|
||||
useGetIPAdapterModelsQuery,
|
||||
useGetLoRAModelsQuery,
|
||||
} from '../../../services/api/endpoints/models';
|
||||
import { loraRecalled, lorasCleared } from '../../lora/store/loraSlice';
|
||||
@ -45,10 +51,10 @@ import {
|
||||
} from '../store/generationSlice';
|
||||
import {
|
||||
isValidCfgScale,
|
||||
isValidHeight,
|
||||
isValidLoRAModel,
|
||||
isValidControlNetModel,
|
||||
isValidHeight,
|
||||
isValidIPAdapterModel,
|
||||
isValidLoRAModel,
|
||||
isValidMainModel,
|
||||
isValidNegativePrompt,
|
||||
isValidPositivePrompt,
|
||||
@ -64,22 +70,18 @@ import {
|
||||
isValidStrength,
|
||||
isValidWidth,
|
||||
} from '../types/parameterSchemas';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import {
|
||||
CONTROLNET_PROCESSORS,
|
||||
CONTROLNET_MODEL_DEFAULT_PROCESSORS,
|
||||
} from 'features/controlNet/store/constants';
|
||||
|
||||
const selector = createSelector(stateSelector, ({ generation }) => {
|
||||
const { model } = generation;
|
||||
return { model };
|
||||
});
|
||||
const selector = createSelector(
|
||||
stateSelector,
|
||||
({ generation }) => generation.model,
|
||||
defaultSelectorOptions
|
||||
);
|
||||
|
||||
export const useRecallParameters = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const toaster = useAppToaster();
|
||||
const { t } = useTranslation();
|
||||
const { model } = useAppSelector(selector);
|
||||
const model = useAppSelector(selector);
|
||||
|
||||
const parameterSetToast = useCallback(() => {
|
||||
toaster({
|
||||
@ -349,13 +351,7 @@ export const useRecallParameters = () => {
|
||||
* Recall LoRA with toast
|
||||
*/
|
||||
|
||||
const { loras } = useGetLoRAModelsQuery(undefined, {
|
||||
selectFromResult: (result) => ({
|
||||
loras: result.data
|
||||
? loraModelsAdapter.getSelectors().selectAll(result.data)
|
||||
: [],
|
||||
}),
|
||||
});
|
||||
const { data: loras } = useGetLoRAModelsQuery(undefined);
|
||||
|
||||
const prepareLoRAMetadataItem = useCallback(
|
||||
(loraMetadataItem: LoRAMetadataItem) => {
|
||||
@ -365,9 +361,11 @@ export const useRecallParameters = () => {
|
||||
|
||||
const { base_model, model_name } = loraMetadataItem.lora;
|
||||
|
||||
const matchingLoRA = loras.find(
|
||||
(l) => l.base_model === base_model && l.model_name === model_name
|
||||
);
|
||||
const matchingLoRA = loras
|
||||
? loraModelsAdapter
|
||||
.getSelectors()
|
||||
.selectById(loras, `${base_model}/lora/${model_name}`)
|
||||
: undefined;
|
||||
|
||||
if (!matchingLoRA) {
|
||||
return { lora: null, error: 'LoRA model is not installed' };
|
||||
@ -410,13 +408,7 @@ export const useRecallParameters = () => {
|
||||
* Recall ControlNet with toast
|
||||
*/
|
||||
|
||||
const { controlnets } = useGetControlNetModelsQuery(undefined, {
|
||||
selectFromResult: (result) => ({
|
||||
controlnets: result.data
|
||||
? controlNetModelsAdapter.getSelectors().selectAll(result.data)
|
||||
: [],
|
||||
}),
|
||||
});
|
||||
const { data: controlNets } = useGetControlNetModelsQuery(undefined);
|
||||
|
||||
const prepareControlNetMetadataItem = useCallback(
|
||||
(controlnetMetadataItem: ControlNetMetadataItem) => {
|
||||
@ -434,11 +426,14 @@ export const useRecallParameters = () => {
|
||||
resize_mode,
|
||||
} = controlnetMetadataItem;
|
||||
|
||||
const matchingControlNetModel = controlnets.find(
|
||||
(c) =>
|
||||
c.base_model === control_model.base_model &&
|
||||
c.model_name === control_model.model_name
|
||||
);
|
||||
const matchingControlNetModel = controlNets
|
||||
? controlNetModelsAdapter
|
||||
.getSelectors()
|
||||
.selectById(
|
||||
controlNets,
|
||||
`${control_model.base_model}/controlnet/${control_model.model_name}`
|
||||
)
|
||||
: undefined;
|
||||
|
||||
if (!matchingControlNetModel) {
|
||||
return { controlnet: null, error: 'ControlNet model is not installed' };
|
||||
@ -491,7 +486,7 @@ export const useRecallParameters = () => {
|
||||
|
||||
return { controlnet, error: null };
|
||||
},
|
||||
[controlnets, model?.base_model]
|
||||
[controlNets, model?.base_model]
|
||||
);
|
||||
|
||||
const recallControlNet = useCallback(
|
||||
@ -523,13 +518,7 @@ export const useRecallParameters = () => {
|
||||
* Recall IP Adapter with toast
|
||||
*/
|
||||
|
||||
const { ipAdapters } = useGetIPAdapterModelsQuery(undefined, {
|
||||
selectFromResult: (result) => ({
|
||||
ipAdapters: result.data
|
||||
? ipAdapterModelsAdapter.getSelectors().selectAll(result.data)
|
||||
: [],
|
||||
}),
|
||||
});
|
||||
const { data: ipAdapters } = useGetIPAdapterModelsQuery(undefined);
|
||||
|
||||
const prepareIPAdapterMetadataItem = useCallback(
|
||||
(ipAdapterMetadataItem: IPAdapterMetadataItem) => {
|
||||
@ -545,11 +534,14 @@ export const useRecallParameters = () => {
|
||||
end_step_percent,
|
||||
} = ipAdapterMetadataItem;
|
||||
|
||||
const matchingIPAdapterModel = ipAdapters.find(
|
||||
(c) =>
|
||||
c.base_model === ip_adapter_model?.base_model &&
|
||||
c.model_name === ip_adapter_model?.model_name
|
||||
);
|
||||
const matchingIPAdapterModel = ipAdapters
|
||||
? ipAdapterModelsAdapter
|
||||
.getSelectors()
|
||||
.selectById(
|
||||
ipAdapters,
|
||||
`${ip_adapter_model.base_model}/ip_adapter/${ip_adapter_model.model_name}`
|
||||
)
|
||||
: undefined;
|
||||
|
||||
if (!matchingIPAdapterModel) {
|
||||
return { ipAdapter: null, error: 'IP Adapter model is not installed' };
|
||||
|
Loading…
Reference in New Issue
Block a user