Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 17 additions & 3 deletions src/hooks/useSearchResults.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,29 @@ import usePrevious from './usePrevious';
* It utilizes `useTransition` to allow the searchQuery to change rapidly, while more expensive renders that occur using
* the result of the filtering and sorting are de-prioritized, allowing them to happen in the background.
*/
function useSearchResults<TValue extends ListItem>(data: TValue[], filterData: (datum: TValue, searchInput: string) => boolean, sortData: (data: TValue[]) => TValue[] = (d) => d) {
function useSearchResults<TValue extends ListItem>(
data: TValue[],
filterData: (datum: TValue, searchInput: string) => boolean,
sortData: (data: TValue[]) => TValue[] = (d) => d,
/**
* Whether to sort data immediately on mount to prevent briefly displaying unsorted data,
* since sorting is handled inside startTransition.
*/
shouldSortInitialData?: boolean,
) {
const [inputValue, setInputValue] = useState('');
const [result, setResult] = useState(data);
const [result, setResult] = useState(() => (shouldSortInitialData ? sortData(data) : data));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should have fixed at other places as well on similar issue. Ref - #70659 (comment)

const prevData = usePrevious(data);
const [, startTransition] = useTransition();
useEffect(() => {
startTransition(() => {
const normalizedSearchQuery = inputValue.trim().toLowerCase();
const filtered = normalizedSearchQuery.length ? data.filter((item) => filterData(item, normalizedSearchQuery)) : data;

// Create shallow copy of data to prevent mutation. When no search query exists, we pass the full dataset
// to sortData. If sortData uses Array.sort() (which sorts in place and returns the same reference),
// the original data array would be mutated. This breaks React's reference equality check in setResult,
// preventing re-renders even when the sort order changes (e.g., on page refresh).
const filtered = normalizedSearchQuery.length ? data.filter((item) => filterData(item, normalizedSearchQuery)) : [...data];
const sorted = sortData(filtered);
setResult(sorted);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ function WorkspaceCompanyCardsList({cardsList, policyID, handleAssignCard, isDis

const filterCard = useCallback((card: Card, searchInput: string) => filterCardsByPersonalDetails(card, searchInput, personalDetails), [personalDetails]);
const sortCards = useCallback((cards: Card[]) => sortCardsByCardholderName(cards, personalDetails), [personalDetails]);
const [inputValue, setInputValue, filteredSortedCards] = useSearchResults(allCards, filterCard, sortCards);
const [inputValue, setInputValue, filteredSortedCards] = useSearchResults(allCards, filterCard, sortCards, true);

const renderItem = useCallback(
({item, index}: ListRenderItemInfo<Card>) => {
Expand Down
Loading