Skip to content

use infinite query max pages limit #712

@linear

Description

@linear

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.ts lines 13-47
  • No maxPages configuration
  • 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

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions