-
Notifications
You must be signed in to change notification settings - Fork 6
Description
status: ready
priority: p1
issue_id: "006"
tags: [performance, react-query, memory, infinite-scroll]
dependencies: []
source: "PR #690 Review"
Add maxPages Limit to React Query Infinite Query
Problem Statement
The infinite query has no maxPages limit, causing unbounded memory growth. React Query keeps ALL pages in memory by default:
- User scrolls 40 pages = 1,000 bookmarks × ~2KB each = ~2MB JSON in memory
- This accumulates until user navigates away
- Combined with DOM rendering (Issue Dev #5), causes severe memory pressure
- Mobile devices with limited memory will struggle
Findings
- File:
src/async/queryHooks/bookmarks/useFetchDiscoverBookmarks.tslines 13-47 - No
maxPagesconfiguration - Each page contains full bookmark objects with image URLs, metadata
- Heavy scrolling sessions can exceed 4MB+ memory usage
- Potential for tab crashes on low-end devices
Current code without limit:
useInfiniteQuery({
queryKey: [BOOKMARKS_KEY, DISCOVER_URL],
queryFn: async ({ pageParam }) => { /* ... */ },
initialPageParam: 0,
getNextPageParam: (lastPage, pages) => {
if (lastPageLength < PAGINATION_LIMIT) return undefined;
return pages.length; // No upper bound!
},
// Missing: maxPages configuration
});Proposed Solutions
Option 1: Simple maxPages (Recommended)
Approach: Add maxPages configuration to useInfiniteQuery.
Pros:
- 5-minute fix
- React Query native feature
- Immediately prevents memory growth
Cons:
- Users lose older pages when scrolling far
- Need to re-fetch if scrolling back
Effort: 15 minutes
Risk: Low
Implementation:
useInfiniteQuery({
queryKey: [BOOKMARKS_KEY, DISCOVER_URL],
queryFn: async ({ pageParam }) => { /* ... */ },
initialPageParam: 0,
maxPages: 20, // Keep max 500 items (20 × 25)
getNextPageParam: (lastPage, pages) => {
const lastPageLength = lastPage?.data?.length ?? 0;
if (lastPageLength < PAGINATION_LIMIT) return undefined;
return pages.length;
},
});Option 2: Dynamic maxPages Based on Device
Approach: Detect device memory and adjust maxPages accordingly.
Pros:
- Better UX on capable devices
- Graceful degradation
Cons:
- More complex
- Device detection not always reliable
Effort: 1-2 hours
Risk: Medium
Option 3: Sliding Window with getPreviousPageParam
Approach: Implement bidirectional infinite scroll with sliding window.
Pros:
- Users can scroll both directions
- Best UX
Cons:
- Most complex implementation
- Requires cursor-based pagination (Issue Dev #4)
Effort: 4-6 hours
Risk: High
Recommended Action
Approved: Option 1 - Simple maxPages = 20. Quick 15-minute fix.
Technical Details
Affected files:
src/async/queryHooks/bookmarks/useFetchDiscoverBookmarks.ts- Add maxPages
Cache behavior with maxPages:
- When scrolling forward past limit, oldest pages are dropped
- If user scrolls back, those pages are re-fetched
- Total cache size bounded to maxPages × PAGINATION_LIMIT items
Recommended values:
- Desktop: maxPages = 20 (500 items)
- Mobile: maxPages = 10 (250 items)
Resources
- PR: feat(bookmark): implement discoverable feature for bookmarks #690
- Performance Review: Performance Oracle agent findings
- TanStack Query Docs: https://tanstack.com/query/latest/docs/react/reference/useInfiniteQuery
Acceptance Criteria
- maxPages is configured on useFetchDiscoverBookmarks
- Memory usage stays bounded during heavy scrolling
- Old pages are dropped when limit exceeded
- Re-fetching works when scrolling back
- No crashes on mobile devices with 1000+ items loaded
Work Log
2025-12-22 - Initial Discovery
By: Performance Oracle Agent (PR #690 Review)
Actions:
- Identified missing maxPages configuration
- Calculated memory impact at scale
- Recommended maxPages = 20 as starting point
- Noted coordination with virtualization (Issue Dev #5)
Learnings:
- React Query's maxPages is perfect for this use case
- Combined with DOM virtualization, creates sliding window effect
- Should test on actual mobile devices
Notes
- Severity: CRITICAL - Memory leak potential
- Effort: Very low - 15 minute fix
- Priority: Should be done immediately as quick win
- Combined with Issue Dev #5 (virtualization) for complete solution