Skip to content

Commit 7ea14fa

Browse files
Add debounced search to platform selector
Co-authored-by: shannon.anahata <[email protected]>
1 parent fab73dd commit 7ea14fa

File tree

1 file changed

+35
-12
lines changed

1 file changed

+35
-12
lines changed

src/components/platformSelector/index.tsx

Lines changed: 35 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
'use client';
2-
import {Fragment, Ref, useEffect, useMemo, useRef, useState} from 'react';
2+
import {Fragment, Ref, useCallback, useEffect, useMemo, useRef, useState} from 'react';
33
import {Combobox, ComboboxItem, ComboboxList, ComboboxProvider} from '@ariakit/react';
44
import {CaretRightIcon, CaretSortIcon, MagnifyingGlassIcon} from '@radix-ui/react-icons';
55
import * as RadixSelect from '@radix-ui/react-select';
@@ -63,26 +63,40 @@ export function PlatformSelector({
6363
const currentPlatformKey = currentPlatform?.key;
6464
const [open, setOpen] = useState(false);
6565
const [searchValue, setSearchValue] = useState('');
66+
const debounceRef = useRef<NodeJS.Timeout>();
67+
68+
// Debounced search handler to prevent rapid re-renders
69+
const debouncedSetSearchValue = useCallback((value: string) => {
70+
if (debounceRef.current) {
71+
clearTimeout(debounceRef.current);
72+
}
73+
debounceRef.current = setTimeout(() => setSearchValue(value), 100);
74+
}, []);
6675

6776
const matches = useMemo(() => {
6877
if (!searchValue) {
6978
return platformsAndGuides;
7079
}
80+
81+
// Find currently selected platform first to ensure it's never filtered out
82+
const selectedPlatform = platformsAndGuides.find(
83+
lang => lang.key === currentPlatformKey
84+
);
85+
86+
// Filter out the selected platform from search, then add it back at the end
87+
const otherPlatforms = platformsAndGuides.filter(
88+
lang => lang.key !== currentPlatformKey
89+
);
90+
7191
// any of these fields can be used to match the search value
7292
const keys = ['title', 'name', 'aliases', 'sdk', 'keywords'];
73-
const matches_ = matchSorter(platformsAndGuides, searchValue, {
93+
const matches_ = matchSorter(otherPlatforms, searchValue, {
7494
keys,
7595
threshold: matchSorter.rankings.ACRONYM,
7696
});
77-
// Radix Select does not work if we don't render the selected item, so we
78-
// make sure to include it in the list of matches.
79-
const selectedPlatform = platformsAndGuides.find(
80-
lang => lang.key === currentPlatformKey
81-
);
82-
if (selectedPlatform && !matches_.includes(selectedPlatform)) {
83-
matches_.push(selectedPlatform);
84-
}
85-
return matches_;
97+
98+
// Always include the selected platform at the beginning
99+
return selectedPlatform ? [selectedPlatform, ...matches_] : matches_;
86100
}, [searchValue, currentPlatformKey, platformsAndGuides]);
87101

88102
const router = useRouter();
@@ -117,6 +131,15 @@ export function PlatformSelector({
117131
setStoredPlatformKey(localStorage.getItem('active-platform'));
118132
}
119133
}, [currentPlatformKey]);
134+
135+
// Cleanup debounce timer on unmount
136+
useEffect(() => {
137+
return () => {
138+
if (debounceRef.current) {
139+
clearTimeout(debounceRef.current);
140+
}
141+
};
142+
}, []);
120143

121144
const path = usePathname();
122145
const isPlatformPage = Boolean(
@@ -144,7 +167,7 @@ export function PlatformSelector({
144167
open={open}
145168
setOpen={setOpen}
146169
includesBaseElement={false}
147-
setValue={setSearchValue}
170+
setValue={debouncedSetSearchValue}
148171
>
149172
<RadixSelect.Trigger aria-label="Platform" className={styles.select}>
150173
<RadixSelect.Value placeholder="Choose your SDK" />

0 commit comments

Comments
 (0)