mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
feat(ui): misc perf/rerender improvements
More efficient selectors, memoized/stable references to objects, lazy popover/menu rendering.
This commit is contained in:
committed by
Kent Keirsey
parent
2ba505cce9
commit
539887b215
@ -7,13 +7,9 @@ import { InvControl } from 'common/components/InvControl/InvControl';
|
||||
import { InvText } from 'common/components/InvText/wrapper';
|
||||
import ScrollableContent from 'common/components/OverlayScrollbars/ScrollableContent';
|
||||
import NotesTextarea from 'features/nodes/components/flow/nodes/Invocation/NotesTextarea';
|
||||
import type {
|
||||
InvocationNode,
|
||||
InvocationTemplate,
|
||||
} from 'features/nodes/types/invocation';
|
||||
import { useNodeNeedsUpdate } from 'features/nodes/hooks/useNodeNeedsUpdate';
|
||||
import { isInvocationNode } from 'features/nodes/types/invocation';
|
||||
import { getNeedsUpdate } from 'features/nodes/util/node/nodeUpdate';
|
||||
import { memo, useMemo } from 'react';
|
||||
import { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import EditableNodeTitle from './details/EditableNodeTitle';
|
||||
@ -30,38 +26,47 @@ const selector = createMemoizedSelector(stateSelector, ({ nodes }) => {
|
||||
? nodes.nodeTemplates[lastSelectedNode.data.type]
|
||||
: undefined;
|
||||
|
||||
if (!isInvocationNode(lastSelectedNode) || !lastSelectedNodeTemplate) {
|
||||
return;
|
||||
}
|
||||
|
||||
return {
|
||||
node: lastSelectedNode,
|
||||
template: lastSelectedNodeTemplate,
|
||||
nodeId: lastSelectedNode.data.id,
|
||||
nodeVersion: lastSelectedNode.data.version,
|
||||
templateTitle: lastSelectedNodeTemplate.title,
|
||||
};
|
||||
});
|
||||
|
||||
const InspectorDetailsTab = () => {
|
||||
const { node, template } = useAppSelector(selector);
|
||||
const data = useAppSelector(selector);
|
||||
const { t } = useTranslation();
|
||||
|
||||
if (!template || !isInvocationNode(node)) {
|
||||
if (!data) {
|
||||
return (
|
||||
<IAINoContentFallback label={t('nodes.noNodeSelected')} icon={null} />
|
||||
);
|
||||
}
|
||||
|
||||
return <Content node={node} template={template} />;
|
||||
return (
|
||||
<Content
|
||||
nodeId={data.nodeId}
|
||||
nodeVersion={data.nodeVersion}
|
||||
templateTitle={data.templateTitle}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(InspectorDetailsTab);
|
||||
|
||||
type ContentProps = {
|
||||
node: InvocationNode;
|
||||
template: InvocationTemplate;
|
||||
nodeId: string;
|
||||
nodeVersion: string;
|
||||
templateTitle: string;
|
||||
};
|
||||
|
||||
const Content = memo(({ node, template }: ContentProps) => {
|
||||
const Content = memo((props: ContentProps) => {
|
||||
const { t } = useTranslation();
|
||||
const needsUpdate = useMemo(
|
||||
() => getNeedsUpdate(node, template),
|
||||
[node, template]
|
||||
);
|
||||
const needsUpdate = useNodeNeedsUpdate(props.nodeId);
|
||||
return (
|
||||
<Box position="relative" w="full" h="full">
|
||||
<ScrollableContent>
|
||||
@ -73,20 +78,20 @@ const Content = memo(({ node, template }: ContentProps) => {
|
||||
p={1}
|
||||
gap={2}
|
||||
>
|
||||
<EditableNodeTitle nodeId={node.data.id} />
|
||||
<EditableNodeTitle nodeId={props.nodeId} />
|
||||
<HStack>
|
||||
<InvControl label={t('nodes.nodeType')}>
|
||||
<InvText fontSize="sm" fontWeight="semibold">
|
||||
{template.title}
|
||||
{props.templateTitle}
|
||||
</InvText>
|
||||
</InvControl>
|
||||
<InvControl label={t('nodes.nodeVersion')} isInvalid={needsUpdate}>
|
||||
<InvText fontSize="sm" fontWeight="semibold">
|
||||
{node.data.version}
|
||||
{props.nodeVersion}
|
||||
</InvText>
|
||||
</InvControl>
|
||||
</HStack>
|
||||
<NotesTextarea nodeId={node.data.id} />
|
||||
<NotesTextarea nodeId={props.nodeId} />
|
||||
</Flex>
|
||||
</ScrollableContent>
|
||||
</Box>
|
||||
|
@ -28,24 +28,31 @@ const selector = createMemoizedSelector(stateSelector, ({ nodes }) => {
|
||||
const nes =
|
||||
nodes.nodeExecutionStates[lastSelectedNodeId ?? '__UNKNOWN_NODE__'];
|
||||
|
||||
if (
|
||||
!isInvocationNode(lastSelectedNode) ||
|
||||
!nes ||
|
||||
!lastSelectedNodeTemplate
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
return {
|
||||
node: lastSelectedNode,
|
||||
template: lastSelectedNodeTemplate,
|
||||
nes,
|
||||
outputs: nes.outputs,
|
||||
outputType: lastSelectedNodeTemplate.outputType,
|
||||
};
|
||||
});
|
||||
|
||||
const InspectorOutputsTab = () => {
|
||||
const { node, template, nes } = useAppSelector(selector);
|
||||
const data = useAppSelector(selector);
|
||||
const { t } = useTranslation();
|
||||
|
||||
if (!node || !nes || !isInvocationNode(node)) {
|
||||
if (!data) {
|
||||
return (
|
||||
<IAINoContentFallback label={t('nodes.noNodeSelected')} icon={null} />
|
||||
);
|
||||
}
|
||||
|
||||
if (nes.outputs.length === 0) {
|
||||
if (data.outputs.length === 0) {
|
||||
return (
|
||||
<IAINoContentFallback label={t('nodes.noOutputRecorded')} icon={null} />
|
||||
);
|
||||
@ -63,15 +70,15 @@ const InspectorOutputsTab = () => {
|
||||
h="full"
|
||||
w="full"
|
||||
>
|
||||
{template?.outputType === 'image_output' ? (
|
||||
nes.outputs.map((result, i) => (
|
||||
{data.outputType === 'image_output' ? (
|
||||
data.outputs.map((result, i) => (
|
||||
<ImageOutputPreview
|
||||
key={getKey(result, i)}
|
||||
output={result as ImageOutput}
|
||||
/>
|
||||
))
|
||||
) : (
|
||||
<DataViewer data={nes.outputs} label={t('nodes.nodeOutputs')} />
|
||||
<DataViewer data={data.outputs} label={t('nodes.nodeOutputs')} />
|
||||
)}
|
||||
</Flex>
|
||||
</ScrollableContent>
|
||||
|
@ -11,20 +11,15 @@ export const useNodeNeedsUpdate = (nodeId: string) => {
|
||||
createMemoizedSelector(stateSelector, ({ nodes }) => {
|
||||
const node = nodes.nodes.find((node) => node.id === nodeId);
|
||||
const template = nodes.nodeTemplates[node?.data.type ?? ''];
|
||||
return { node, template };
|
||||
if (isInvocationNode(node) && template) {
|
||||
return getNeedsUpdate(node, template);
|
||||
}
|
||||
return false;
|
||||
}),
|
||||
[nodeId]
|
||||
);
|
||||
|
||||
const { node, template } = useAppSelector(selector);
|
||||
|
||||
const needsUpdate = useMemo(
|
||||
() =>
|
||||
isInvocationNode(node) && template
|
||||
? getNeedsUpdate(node, template)
|
||||
: false,
|
||||
[node, template]
|
||||
);
|
||||
const needsUpdate = useAppSelector(selector);
|
||||
|
||||
return needsUpdate;
|
||||
};
|
||||
|
Reference in New Issue
Block a user