-
-
Notifications
You must be signed in to change notification settings - Fork 54.6k
Select v6 searchValue is removed when options are updated with onSearch #55968
Copy link
Copy link
Closed
Closed
Copy link
Labels
6.x🐛 BugAnt Design Team had proved that this is a bug.Ant Design Team had proved that this is a bug.
Description
Reproduction link
Steps to reproduce
- Create a Select component with showSearch enabled and async options loading
- Use onSearch to trigger an API call (debounced) that updates the options prop
- Type a search query (e.g., "test")
- Wait for the API response to return and update the options
import { useState } from 'react';
import { Select } from 'antd';
import { useQuery, QueryClient, QueryClientProvider } from '@tanstack/react-query';
import debounce from 'lodash-es/debounce';
const queryClient = new QueryClient();
// Simulated API call
const fetchOptions = async (query: string) => {
await new Promise((resolve) => setTimeout(resolve, 500));
return [
{ value: '1', label: `Result 1 for "${query}"` },
{ value: '2', label: `Result 2 for "${query}"` },
];
};
const AsyncSelect = () => {
const [searchTerm, setSearchTerm] = useState('');
const [debouncedSearchTerm, setDebouncedSearchTerm] = useState('');
const { data: options = [], isFetching } = useQuery({
queryKey: ['options', debouncedSearchTerm],
queryFn: () => fetchOptions(debouncedSearchTerm),
enabled: debouncedSearchTerm.length >= 3,
});
const debouncedSetSearch = debounce((value: string) => {
setDebouncedSearchTerm(value);
}, 300);
const handleSearch = (value: string) => {
setSearchTerm(value);
debouncedSetSearch(value);
};
return (
<Select
showSearch
style={{ width: 300 }}
placeholder="Search..."
options={options}
loading={isFetching}
onSearch={handleSearch}
filterOption={false}
/>
);
};
const App = () => (
<QueryClientProvider client={queryClient}>
<AsyncSelect />
</QueryClientProvider>
);
What is expected?
When the user types "John Doe" and the API returns results, the search input should retain the value "test" and display the filtered options below, with the combobox opened.
What is actually happening?
Intermittently, when the options are updated after the API call returns, the search input value is cleared (reset to empty string). This happens inconsistently - sometimes the search value persists correctly, other times it gets wiped out.
The issue appears to be in rc-select's internal state management. When options update and trigger a re-render, onSearch('') is called internally, which clears the search input, hiding the options in consequence.
| Environment | Info |
|---|---|
| antd | 6.0.0 |
| React | 19.2 |
| System | MacOS |
| Browser | Chrome 142.0.7444.176 |
- Intermittent nature: The bug doesn't happen 100% of the time, making it harder to reproduce consistently. It seems related to timing/race conditions between the options update and internal state management.
Root cause investigation: The issue appears to stem from rc-select replacing useMergedState with useControlledState for managing searchValue. The older implementation handled controlled/uncontrolled state more robustly:
// Old (worked correctly):
const [mergedSearchValue, setSearchValue] = useMergedState('', {
value: searchValue !== undefined ? searchValue : inputValue,
postState: (search) => search || '',
});
// New (causes the bug):
const [internalSearchValue, setSearchValue] = useControlledState('', searchValue);
- Workaround: The issue can be worked around by making the search input fully controlled via showSearch={{ searchValue, onSearch }} and guarding against internal empty string resets:
const [searchValue, setSearchValue] = useState('');
const handleSearch = (value: string) => {
// Guard against rc-select internal resets
if (value === '' && searchValue.length > 1) {
return;
}
setSearchValue(value);
};
<Select
showSearch={{ searchValue, onSearch: handleSearch }}
// ...
/>
- Environment: antd v6.x, React 19.x
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
6.x🐛 BugAnt Design Team had proved that this is a bug.Ant Design Team had proved that this is a bug.