Skip to content

Instantly share code, notes, and snippets.

@tiarebalbi
Created October 9, 2024 13:06
Show Gist options
  • Select an option

  • Save tiarebalbi/21479cc9689ddbc2be1675ff18083644 to your computer and use it in GitHub Desktop.

Select an option

Save tiarebalbi/21479cc9689ddbc2be1675ff18083644 to your computer and use it in GitHub Desktop.
import React, { useEffect, useMemo, useRef, useState } from 'react';
import type { SelectProps } from 'antd';
import { Select, Spin } from 'antd';
import { debounce } from 'lodash';
export type Entry = {
label: string;
value: string;
};
export interface DebounceSelectProps
extends Omit<SelectProps<Entry | Entry[]>, 'options' | 'children'> {
fetchOptions: (search: string) => Promise<Entry[]>;
debounceTimeout?: number;
}
export const DebounceSelect: React.FC<DebounceSelectProps> = ({
fetchOptions,
debounceTimeout = 300,
...props
}) => {
const [fetching, setFetching] = useState(false);
const [options, setOptions] = useState<Entry[]>([]);
const fetchRef = useRef(0);
const debounceFetcher = useMemo(() => {
const loadOptions = (value: string) => {
fetchRef.current += 1;
const fetchId = fetchRef.current;
setOptions([]);
setFetching(true);
fetchOptions(value).then((newOptions) => {
if (fetchId !== fetchRef.current) {
// for fetch callback order
return;
}
setOptions(newOptions);
setFetching(false);
});
};
return debounce(loadOptions, debounceTimeout);
}, [fetchOptions, debounceTimeout]);
useEffect(() => {
debounceFetcher('');
}, [debounceFetcher, props.value]);
return (
<Select
defaultActiveFirstOption={true}
onSearch={debounceFetcher}
notFoundContent={fetching ? <Spin size="small" /> : null}
{...props}
options={options}
/>
);
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment