Skip to content

Commit

Permalink
perf: improve render performance of fields
Browse files Browse the repository at this point in the history
Running the dispatcher on each change is expensive, and waiting for it to run before showing the user's input creates a significant lag.

This change uses local state for all inputs, to give the user immediate feedback, and debounces the dispatcher call.

useDeferredValue doesn't help us here, since the reducer is expensive regardless of the UI render.
  • Loading branch information
chrisvxd committed Nov 3, 2023
1 parent 7f13efc commit d92de7f
Showing 1 changed file with 28 additions and 11 deletions.
39 changes: 28 additions & 11 deletions packages/core/components/InputOrGroup/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import getClassNameFactory from "../../lib/get-class-name-factory";
import { Field } from "../../types/Config";

import styles from "./styles.module.css";
import { ReactNode } from "react";
import { ReactNode, useCallback, useEffect, useState } from "react";
import {
RadioField,
SelectField,
Expand All @@ -12,6 +12,7 @@ import {
TextareaField,
} from "./fields";
import { Lock } from "react-feather";
import { useDebouncedCallback, useDebounce } from "use-debounce";

const getClassName = getClassNameFactory("Input", styles);

Expand Down Expand Up @@ -85,27 +86,44 @@ export type InputProps = {
readOnlyFields?: Record<string, boolean | undefined>;
};

export const InputOrGroup = (props: InputProps) => {
const { name, field, value, onChange, readOnly } = props;
export const InputOrGroup = ({ onChange, ...props }: InputProps) => {
const { name, field, value, readOnly } = props;

const [localValue, setLocalValue] = useState(value);

const [localValueDb] = useDebounce(localValue, 50, { leading: true });

useEffect(() => {
onChange(localValueDb);
}, [localValueDb]);

const onChangeLocal = useCallback((val) => {
setLocalValue(val);
}, []);

const localProps = {
value: localValue,
onChange: onChangeLocal,
};

if (field.type === "array") {
return <ArrayField {...props} />;
return <ArrayField {...props} {...localProps} />;
}

if (field.type === "external") {
return <ExternalField {...props} />;
return <ExternalField {...props} {...localProps} />;
}

if (field.type === "select") {
return <SelectField {...props} />;
return <SelectField {...props} {...localProps} />;
}

if (field.type === "textarea") {
return <TextareaField {...props} />;
return <TextareaField {...props} {...localProps} />;
}

if (field.type === "radio") {
return <RadioField {...props} />;
return <RadioField {...props} {...localProps} />;
}

if (field.type === "custom") {
Expand All @@ -118,13 +136,12 @@ export const InputOrGroup = (props: InputProps) => {
{field.render({
field,
name,
value,
onChange,
readOnly,
...localProps,
})}
</div>
);
}

return <DefaultField {...props} />;
return <DefaultField {...props} {...localProps} />;
};

0 comments on commit d92de7f

Please sign in to comment.