Skip to content

Commit fc8cf22

Browse files
authored
Merge pull request #278 from KxlSys/bolt-usememo-admin-places-2245395720471195122
⚡ Bolt: [performance improvement]
2 parents 3094c72 + d0de135 commit fc8cf22

2 files changed

Lines changed: 9 additions & 6 deletions

File tree

.jules/bolt.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818
**Learning:** The `DebouncedInput` component was used in several places to prevent excessive parent re-renders while typing. However, because `DebouncedInput` itself was not wrapped in `React.memo()`, it was still re-rendering unnecessarily whenever its parent components re-rendered for reasons unrelated to the input (e.g. other form fields changing, complex page state updates). This unnecessary re-rendering could destroy and recreate its internal debouncing logic and cause extra reconciliation work.
1919
**Action:** When creating utility wrapper components designed to optimize performance (like `DebouncedInput`), ensure the component itself is memoized with `React.memo()` so it fully shields itself from irrelevant parent state updates.
2020

21-
## 2024-07-09 - Avoid Multiple Array Iterations for Data Aggregation
22-
**Learning:** In functions like `computeStats` (in `about-page.tsx` and `use-platform-stats.ts`) that compute multiple aggregate metrics from an array of objects, chaining methods like `.map().filter()`, `.flatMap()`, or doing multiple explicit `for` loops across the entire dataset causes unnecessary intermediate array allocations and redundant O(n) passes. In extreme cases, doing this 8-10 times over a large dataset blocks the main thread.
23-
**Action:** Always consolidate multiple map/reduce/filter operations into a single O(n) `for` loop. Keep multiple accumulator dictionaries/counters and update them all at once per item. Also, derive counts (like total distinct items) directly from the keys/size of the accumulators instead of recalculating them from the original array.
21+
## 2024-07-10 - O(n) Single Pass Data Aggregation
22+
**Learning:** Using chained array methods (e.g. `.map().filter()`, `.flatMap()`, and repeated `.filter()` over the same large list like `profiles`) leads to redundant O(n) passes over data and allocates unnecessary intermediate arrays. This blocks the main thread longer than necessary when calculating basic statistics like `uniqueCities`, `uniqueTechs`, or total counts.
23+
**Action:** Consolidate statistical aggregations over large object arrays into a single O(n) `for` loop that updates multiple accumulators (like `Set` objects and primitive counters) in one pass, thereby improving performance and reducing memory overhead.
24+
## 2024-07-20 - Memoization of filtering logic
25+
**Learning:** In pages with heavily interactive inputs (like `AdminPage` with a search bar), performing O(N) array filtering synchronously within the component body causes the expensive calculation to block every re-render, compounding latency on keystrokes.
26+
**Action:** Wrap any O(N) filtering operations (e.g. `profiles.filter(...)`) in `React.useMemo` to ensure they only re-run when their specific dependencies (`profiles` or `searchQuery`) actually change, completely skipping the overhead on unrelated state updates.

src/pages/admin-page.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useEffect, useState } from "react";
1+
import { useEffect, useState, useMemo } from "react";
22
import { useNavigate, Link } from "react-router-dom";
33
import { Shield, Send, UserPlus, UserMinus, Users, Building2, Handshake, Download, Search, TrendingUp, ArrowUpRight, TriangleAlert, Clock, GitCommitHorizontal, UserRoundPlus, Layers as Layers3, Flag, UserCheck, MapPin, Trash2 } from "lucide-react";
44
import { Button } from "@/components/ui/button";
@@ -171,11 +171,11 @@ export function AdminPage() {
171171
);
172172
}
173173

174-
const filteredProfiles = profiles.filter((p) => {
174+
const filteredProfiles = useMemo(() => profiles.filter((p) => {
175175
if (!searchQuery) return true;
176176
const q = searchQuery.toLowerCase();
177177
return p.full_name.toLowerCase().includes(q) || p.username.toLowerCase().includes(q) || p.city?.toLowerCase().includes(q);
178-
});
178+
}), [profiles, searchQuery]);
179179

180180
// ⚡ Bolt: Consolidate data aggregation into a single O(n) pass
181181
// Avoids multiple redundant iterations and intermediate array allocations

0 commit comments

Comments
 (0)