Using ant Select, I've written a component, which has two modes. first: it takes options which is select data. and display it(this part is working fine). second: it takes a select_url and the component itself sends request to fetch data from server. Every thing works fine except when I search characters, sometimes the list popup doesn't show up!!!! which is un expected. I'm sure data reaches the setOptions and even _options has data, but it doesn't show up. but, when I search numbers, it works fine!
I'm new to react, I used to use Vuejs. is it possible that I'm not using react properly ?
Every thing works fine except when I search characters, sometimes the list popup doesn't show up!!!! which is un expected. I'm sure data reaches the setOptions and even _options has data, but it doesn't show up. but, when I search numbers, it works fine!
here is my hole component:
import React, {useEffect, useState} from "react";
import {Select, Spin} from "antd";
import {SelectOption} from "../../@types/app";
interface CustomSelectProps {
options?: SelectOption[],
placeholder?: string,
select_url?: string
}
const CustomSelect: React.FC<CustomSelectProps> = (
{
options,
placeholder = "انتخاب کنید",
select_url
}
) => {
const [_options, setOptions] = useState<undefined | SelectOption[]>(options);
const [nextPageUrl, setNextPageUrl] = useState<string | null>(null);
const [loading, setLoading] = useState<boolean>(false);
useEffect(() => {
if (select_url) {
search()
} else if (options && !select_url) {
setOptions(options);
} else {
// todo: notify user, that this component needs at least one of options || select_url.
console.log("specify data. SELECT");
}
}, []);
const search = async (input: string = '') => {
if (!select_url) return;
setLoading(true);
setOptions(() => []);
const url = `${select_url}?search=${input}&page=1`;
try {
const response = await fetch(url);
if (!response.ok) {
return new Error(`Network response was not ok (${response.status})`);
}
const data = await response.json();
setNextPageUrl(data.next);
setOptions(prevOptions => [...prevOptions, ...data.data]);
} catch (error) {
console.error('Error fetching data:', error);
} finally {
setLoading(false);
}
};
const handlePopupScroll = async (e: React.UIEvent<HTMLDivElement>) => {
if (!select_url) return;
const popupContainer = e.currentTarget;
const isAtEndOfScroll = popupContainer.scrollTop + popupContainer.clientHeight === popupContainer.scrollHeight;
if (isAtEndOfScroll && nextPageUrl && !loading) {
try {
const res = await (await fetch(nextPageUrl)).json();
setNextPageUrl(res.next);
const {data} = res;
setOptions((prevState) => {
return [...prevState, ...data];
});
} catch (e) {
console.log(e);
} finally {
setLoading(false);
}
}
}
// filter options based on user input in client mode.
const handleFilterOption = (input: string, option?: SelectOption) => (option?.label ?? '').toLowerCase().includes(input.toLowerCase());
return (
<Select
options={_options}
placeholder={placeholder}
showSearch={true}
filterOption={select_url ? undefined : handleFilterOption}
onSearch={search}
notFoundContent={loading ? <Spin size="small"/> : null}
virtual={true}
onPopupScroll={handlePopupScroll}
>
</Select>
);
}
export default CustomSelect;
and here is how data comes:
[
{ label: "test", value: "value", key: "1" },
]
You should use optionFilterProp
to select where select
component will search and filter based on what are you typing.
As said in docs:
optionFilterProp
- Which prop value of option will be used for filter if filterOption is true. Ifoptions
is set, it should be set tolabel
Hope this helps :)