Skip to content

Instantly share code, notes, and snippets.

@brandonscript
Last active April 5, 2025 18:08
Show Gist options
  • Save brandonscript/34ef9d47b513439511b464e50917c17a to your computer and use it in GitHub Desktop.
Save brandonscript/34ef9d47b513439511b464e50917c17a to your computer and use it in GitHub Desktop.
A debounced TextField component for React + MaterialUI
import { TextField, type TextFieldProps } from "@mui/material";
import { forwardRef, useImperativeHandle, useState } from "react";
import { type Options as UseDebouncedCallbackOptions, useDebouncedCallback } from "use-debounce";
export type DebouncedTextFieldRef = {
cancelDebounce?: () => void;
clear: () => void;
};
type DebouncedTextFieldProps = TextFieldProps & {
debounceTime?: number;
debounceOptions?: UseDebouncedCallbackOptions;
};
export const DebouncedTextField = forwardRef<DebouncedTextFieldRef, DebouncedTextFieldProps>(
({ value, onChange = () => {}, debounceTime, debounceOptions, ...props }, ref) => {
const [localValue, setLocalValue] = useState(value);
const handleOnChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setLocalValue(e.target.value);
debouncedOnChange(e);
};
const debouncedOnChange = useDebouncedCallback<typeof handleOnChange>(
onChange,
debounceTime ?? 500,
debounceOptions,
);
useImperativeHandle(ref, () => ({
cancelDebounce: debouncedOnChange.cancel,
clear: () => {
setLocalValue("");
debouncedOnChange.cancel();
},
}));
useEffect(() => {
if (value !== localValue) {
setLocalValue(value);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [value]);
return <TextField value={localValue} onChange={handleOnChange} {...props} />;
},
);
DebouncedTextField.displayName = "DebouncedTextField";
import { useState } from "react";
import { type Options as UseDebouncedCallbackOptions, useDebounce, useDebouncedCallback } from "use-debounce";
export const useDebouncedSetState = <T>(
initialState: T,
debounceTime?: number,
debounceOptions?: UseDebouncedCallbackOptions,
) => {
const [state, setState] = useState<T>(initialState);
const debouncedSetState = useDebouncedCallback(setState, debounceTime, debounceOptions);
return [state, debouncedSetState] as const;
};
export const useDebouncedState = <T>(initialState: T, delay: number, debounceOptions?: UseDebouncedCallbackOptions) => {
const [state, setState] = useState<T>(initialState);
const [debouncedState, debounce] = useDebounce(state, delay, debounceOptions);
return [debouncedState, setState, debounce] as const;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment