mirror of
https://github.com/invoke-ai/InvokeAI.git
synced 2026-02-02 10:45:23 -05:00
perf(ui): optimize checking if a field value is changed by wrapping in single selector
This commit is contained in:
@@ -1,19 +1,29 @@
|
|||||||
import { useAppDispatch } from 'app/store/storeHooks';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import { useInputFieldTemplate } from 'features/nodes/hooks/useInputFieldTemplate';
|
import { useInputFieldTemplate } from 'features/nodes/hooks/useInputFieldTemplate';
|
||||||
import { useInputFieldValue } from 'features/nodes/hooks/useInputFieldValue';
|
|
||||||
import { fieldValueReset } from 'features/nodes/store/nodesSlice';
|
import { fieldValueReset } from 'features/nodes/store/nodesSlice';
|
||||||
|
import { selectNodesSlice } from 'features/nodes/store/selectors';
|
||||||
|
import { isInvocationNode } from 'features/nodes/types/invocation';
|
||||||
import { isEqual } from 'lodash-es';
|
import { isEqual } from 'lodash-es';
|
||||||
import { useCallback, useMemo } from 'react';
|
import { useCallback, useMemo } from 'react';
|
||||||
|
|
||||||
export const useInputFieldDefaultValue = (nodeId: string, fieldName: string) => {
|
export const useInputFieldDefaultValue = (nodeId: string, fieldName: string) => {
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
|
|
||||||
const value = useInputFieldValue(nodeId, fieldName);
|
|
||||||
const fieldTemplate = useInputFieldTemplate(nodeId, fieldName);
|
const fieldTemplate = useInputFieldTemplate(nodeId, fieldName);
|
||||||
|
const selectIsChanged = useMemo(
|
||||||
const isValueChanged = useMemo(() => {
|
() =>
|
||||||
return !isEqual(value, fieldTemplate.default);
|
createSelector(selectNodesSlice, (nodes) => {
|
||||||
}, [value, fieldTemplate.default]);
|
const node = nodes.nodes.find((node) => node.id === nodeId);
|
||||||
|
if (!isInvocationNode(node)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const value = node.data.inputs[fieldName]?.value;
|
||||||
|
return !isEqual(value, fieldTemplate.default);
|
||||||
|
}),
|
||||||
|
[fieldName, fieldTemplate.default, nodeId]
|
||||||
|
);
|
||||||
|
const isValueChanged = useAppSelector(selectIsChanged);
|
||||||
|
|
||||||
const resetToDefaultValue = useCallback(() => {
|
const resetToDefaultValue = useCallback(() => {
|
||||||
dispatch(fieldValueReset({ nodeId, fieldName, value: fieldTemplate.default }));
|
dispatch(fieldValueReset({ nodeId, fieldName, value: fieldTemplate.default }));
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import { useInputFieldValue } from 'features/nodes/hooks/useInputFieldValue';
|
|
||||||
import { fieldValueReset } from 'features/nodes/store/nodesSlice';
|
import { fieldValueReset } from 'features/nodes/store/nodesSlice';
|
||||||
|
import { selectNodesSlice } from 'features/nodes/store/selectors';
|
||||||
import { selectWorkflowSlice } from 'features/nodes/store/workflowSlice';
|
import { selectWorkflowSlice } from 'features/nodes/store/workflowSlice';
|
||||||
|
import { isInvocationNode } from 'features/nodes/types/invocation';
|
||||||
import { isEqual } from 'lodash-es';
|
import { isEqual } from 'lodash-es';
|
||||||
import { useCallback, useMemo } from 'react';
|
import { useCallback, useMemo } from 'react';
|
||||||
|
|
||||||
@@ -21,11 +22,22 @@ export const useInputFieldInitialFormValue = (elementId: string, nodeId: string,
|
|||||||
[elementId]
|
[elementId]
|
||||||
);
|
);
|
||||||
const initialValue = useAppSelector(selectInitialValue);
|
const initialValue = useAppSelector(selectInitialValue);
|
||||||
const value = useInputFieldValue(nodeId, fieldName);
|
const selectIsChanged = useMemo(
|
||||||
const isValueChanged = useMemo(
|
() =>
|
||||||
() => initialValue !== uniqueNonexistentValue && !isEqual(value, initialValue),
|
createSelector(selectNodesSlice, (nodes) => {
|
||||||
[value, initialValue]
|
if (initialValue === uniqueNonexistentValue) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const node = nodes.nodes.find((node) => node.id === nodeId);
|
||||||
|
if (!isInvocationNode(node)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const value = node.data.inputs[fieldName]?.value;
|
||||||
|
return !isEqual(value, initialValue);
|
||||||
|
}),
|
||||||
|
[fieldName, initialValue, nodeId]
|
||||||
);
|
);
|
||||||
|
const isValueChanged = useAppSelector(selectIsChanged);
|
||||||
const resetToInitialValue = useCallback(() => {
|
const resetToInitialValue = useCallback(() => {
|
||||||
if (initialValue === uniqueNonexistentValue) {
|
if (initialValue === uniqueNonexistentValue) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -1,23 +0,0 @@
|
|||||||
import { createSelector } from '@reduxjs/toolkit';
|
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
|
||||||
import { selectNodesSlice } from 'features/nodes/store/selectors';
|
|
||||||
import { isInvocationNode } from 'features/nodes/types/invocation';
|
|
||||||
import { useMemo } from 'react';
|
|
||||||
|
|
||||||
export const useInputFieldValue = (nodeId: string, fieldName: string) => {
|
|
||||||
const selector = useMemo(
|
|
||||||
() =>
|
|
||||||
createSelector(selectNodesSlice, (nodes) => {
|
|
||||||
const node = nodes.nodes.find((node) => node.id === nodeId);
|
|
||||||
if (!isInvocationNode(node)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
return node?.data.inputs[fieldName]?.value;
|
|
||||||
}),
|
|
||||||
[fieldName, nodeId]
|
|
||||||
);
|
|
||||||
|
|
||||||
const value = useAppSelector(selector);
|
|
||||||
|
|
||||||
return value;
|
|
||||||
};
|
|
||||||
Reference in New Issue
Block a user