Closed mr-scrpt closed 10 months ago
Did you use onSearch
prop ?
I think this prop fits your needs.
there's a similar code currently.
useEffect(() => {
const exec = async () => {
if (!debouncedSearchTerm || !onSearch) return;
setIsLoading(true);
const res = await onSearch?.(debouncedSearchTerm);
setOptions(transToGroupOption(res, groupBy)); // <----- here
setIsLoading(false);
};
void exec();
}, [debouncedSearchTerm]);
I've added a prop triggerSearchOnFocus
which might fit most use cases and refactored the onSearch
executed condition.
Here is the usage.
It seems like there might be a potential issue with using !debouncedSearchTerm
inside the useEffect
that could lead to unexpected situations.
Hi. I don't understand what a search has to do with my problem. Here code:
<FormField
control={form.control}
name="optionList"
render={({ field }) => {
return (
<FormItem>
<FormLabel>Option</FormLabel>
<FormControl>
<MultipleSelector
value={field.value}
onChange={field.onChange}
options={optionList}
placeholder="Select option to category"
emptyIndicator={
<p className="text-center text-lg leading-10 text-gray-600 dark:text-gray-400">
no results found.
</p>
}
/>
</FormControl>
<FormMessage />
</FormItem>
);
}}
/>
This is where I pass on the list of options options={optionList}
The problem is that this list is initially empty, and after some time, when the request to the server is executed, this list gets the required data - this happens asynchronously
But the MultipleSelector component does not respond to props changes options
const [options, setOptions] = React.useState<GroupOption>(
transToGroupOption(arrayOptions, groupBy),
);
Since it moves it to the state during initialization and works with the stateit already Therefore, when you change the props, you need to update the stack with new data.
useEffect(() => {
setOptions(transToGroupOption(arrayOptions, groupBy));
}, [arrayOptions, groupBy]);
You have to put your request in onSearch
prop and return a GroupOtion[]
value.
Just return the api res in onSearch
prop and the component will trigger setOption
.
<MultipleSelector
// start here-----------------
onSearch={async (value) => {
const res = await mockSearch(value); // Your API.
return res; // return a value which type is `GroupOtions`.
}}
triggerSearchOnFocus // You may need the prop to get init options when `onFocus`
// end here-----------------
placeholder="trying to search 'a' to get more options..."
loadingIndicator={<p>loading...</p>}
emptyIndicator={<p>no results found.</p>}
/>
I still can't understand what search has to do with it - I'm not searching for anything. My request to api is executed through server action in zustand, then it is passed to child component in props where MultipleSelector is located. The initiating state for the options is an empty array, when the request is executed, the zustand storage will be mutated, and the necessary options will appear there for me to select from.
I got it. You are right about the useEffect
snippet.
I didn't do this useEffect
because I was afraid of the performance issue of multiple re-renders.
I will add a JSON.stringify
to avoid the same value re-render and to refactor original options
to defaultOptions
.
useEffect(() => {
/** If `onSearch` is provided, do not trigge options updated. */
if (!arrayOptions || onSearch) {
return;
}
const newOption = transToGroupOption(arrayOptions || [], groupBy);
if (JSON.stringify(newOption) !== JSON.stringify(options)) {
setOptions(newOption);
}
}, [arrayDefaultOptions, arrayOptions, groupBy, onSearch, options]);
here is the usage
My data for the list comes from the backend and initially the options are an empty array and when the response comes from the backend the Multiple Selector component was not updating the list, I added this code and now the data has become reactive