Skip to content

Commit 7d5710c

Browse files
feat: optimize CategoryFilterWidget array iterations
Refactor array methods in CategoryFilterWidget to use a single loop for computing activeCategories and uniqueProfiles. This eliminates intermediate array allocations and improves performance when rendering large amounts of shortcuts. Co-authored-by: alazndy <78882672+alazndy@users.noreply.github.com>
1 parent 7593f90 commit 7d5710c

10 files changed

Lines changed: 49 additions & 35 deletions

.jules/bolt.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,7 @@
55
## 2025-03-09 - Replace .map() with point updates for React state arrays
66
**Learning:** For updating single items in small React state arrays (e.g., layout configurations or task lists), using `array.map()` introduces significant performance overhead by iterating through the entire array and calling the callback for every element. This causes unnecessary processing.
77
**Action:** Prefer "point updates" using `findIndex` and array spreading over `array.map()`. This minimizes object allocations and improves fluidity, especially on lower-power devices.
8+
9+
## 2025-03-09 - Consolidate Multiple Array Iterations into Single Loop
10+
**Learning:** Chaining array methods like `.map()` and `.flatMap()` combined with `new Set()` multiple times on a large data source causes significant performance degradation because each method creates intermediate arrays and iterates over the data multiple times.
11+
**Action:** When deriving multiple sets of data from the same source array, use a single `for...of` loop inside a single `useMemo` block to minimize iterations and avoid unnecessary object allocations.

components/CategoryFilterWidget.tsx

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,21 @@ import { UsersIcon } from '@heroicons/react/24/outline';
66
export const CategoryFilterWidget: React.FC = () => {
77
const { shortcuts, filterCategory, setFilterCategory, filterProfile, setFilterProfile } = useGTab();
88

9-
const activeCategories = useMemo(() => {
10-
return ['All', ...new Set(shortcuts.map(s => s.category))];
11-
}, [shortcuts]);
12-
13-
const uniqueProfiles = useMemo(() => {
14-
return Array.from(new Set(shortcuts.flatMap(s => s.profiles?.map(p => p.name) || []))).sort();
9+
const { activeCategories, uniqueProfiles } = useMemo(() => {
10+
const categoriesSet = new Set<string>();
11+
const profilesSet = new Set<string>();
12+
for (const s of shortcuts) {
13+
if (s.category) categoriesSet.add(s.category);
14+
if (s.profiles) {
15+
for (const p of s.profiles) {
16+
if (p.name) profilesSet.add(p.name);
17+
}
18+
}
19+
}
20+
return {
21+
activeCategories: ['All', ...categoriesSet],
22+
uniqueProfiles: Array.from(profilesSet).sort()
23+
};
1524
}, [shortcuts]);
1625

1726
return (
Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist-store/assets/BackgroundSettingsModal-B5X-Q6xJ.js renamed to dist-store/assets/BackgroundSettingsModal-DLn0MpXH.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)