Description
Several React hooks and services have memory leak risks due to missing cleanup, unbounded data structures, and race conditions with async operations.
Affected Files
packages/frontend/hooks/usePresence.ts:22, 43, 46-55
packages/frontend/services/socketService.ts:565-567, 949-1050
Problems
1. usePresence: setState on unmounted component (usePresence.ts:22)
socketService.getPresence(userId)
.then(setIsOnline) // Can fire after component unmounts
.catch(() => setIsOnline(false));
No AbortController or cleanup flag to prevent setState after unmount.
2. usePresenceBulk: unstable dependency causes re-subscriptions (usePresence.ts:46-55)
useEffect(() => {
// Creates new subscriptions...
return () => {
unsubscribes.forEach(unsubscribe => unsubscribe());
};
}, [userIds.join(',')]); // String join creates new value each render
userIds.join(',') creates a new string reference on each render, potentially causing infinite re-subscription loops.
3. Socket service listener Maps grow unbounded (socketService.ts:949-1050)
presenceListeners and followListeners Maps have a MAX of 500 entries, but if consumers forget to unsubscribe, the map keeps growing until the limit. Unsubscribe functions may never be called for components that unmount without cleanup.
4. Feed update queue unbounded growth (socketService.ts:565-567)
if (currentQueue.length > this.MAX_BATCH_SIZE * 2) {
this.feedUpdateQueue.set(feedType, posts.slice(-this.MAX_BATCH_SIZE));
}
Queue can grow to MAX_BATCH_SIZE * 2 before any trimming occurs.
Expected Behavior
- Add cleanup flags or AbortController to all async operations in useEffect
- Use
useMemo or useRef for stable dependency references
- Enforce strict listener limits with automatic cleanup of oldest entries
- Trim feed queue more aggressively or use a fixed-size ring buffer
Impact
- Severity: Medium
- Risk: Gradual memory growth, React warnings about setState on unmounted components, potential performance degradation over time
Description
Several React hooks and services have memory leak risks due to missing cleanup, unbounded data structures, and race conditions with async operations.
Affected Files
packages/frontend/hooks/usePresence.ts:22, 43, 46-55packages/frontend/services/socketService.ts:565-567, 949-1050Problems
1. usePresence: setState on unmounted component (usePresence.ts:22)
No AbortController or cleanup flag to prevent setState after unmount.
2. usePresenceBulk: unstable dependency causes re-subscriptions (usePresence.ts:46-55)
userIds.join(',')creates a new string reference on each render, potentially causing infinite re-subscription loops.3. Socket service listener Maps grow unbounded (socketService.ts:949-1050)
presenceListenersandfollowListenersMaps have a MAX of 500 entries, but if consumers forget to unsubscribe, the map keeps growing until the limit. Unsubscribe functions may never be called for components that unmount without cleanup.4. Feed update queue unbounded growth (socketService.ts:565-567)
Queue can grow to
MAX_BATCH_SIZE * 2before any trimming occurs.Expected Behavior
useMemooruseReffor stable dependency referencesImpact