Skip to content

fix(chat): forward pagination — keep position + keep loading (JS-9822)#2279

Merged
requilence merged 2 commits into
developfrom
fix/chat-forward-prefetch-stall
Jul 4, 2026
Merged

fix(chat): forward pagination — keep position + keep loading (JS-9822)#2279
requilence merged 2 commits into
developfrom
fix/chat-forward-prefetch-stall

Conversation

@requilence

Copy link
Copy Markdown
Contributor

Forward (load-newer) counterparts to the top-edge fixes from #2276. Reproduce by scrolling a chat up (evicting the newest tail), then scrolling back down.

Problems

  1. Snaps to the batch end, losing your place. scrollToBottomCheck (stick-to-bottom, meant for the live tail) fires whenever isBottom.current is true. During forward pagination onScroll re-sets isBottom=true at the loaded bottom, so each appended batch snaps the view to the batch end — you land back at the bottom with nothing below to scroll into, so loading can't continue.
  2. Fast scroll (PageDown) to the hard bottom stalls. The load-newer prefetch is scroll-event driven; once you stop at the bottom it can't re-fire, so newer batches never load.

Fixes

  • Gate stick-to-bottom on isAtChatEnd — only follow the bottom when at the chat's newest. During pagination the appended rows stay below the current position (default append-below keeps scrollTop), so the view stays put and you scroll down through them; reaching the true newest still snaps.
  • Chain the next forward load after one lands near the bottom, so a fast PageDown that stops at the edge keeps loading. Bounded: stops once ~2 viewports are buffered, at the chat end, or when you scroll away. Epoch-guarded (drops after a window reset), progress-gated (a no-progress page can't spin), and cancelled on unmount (the #page container outlives the chat).

The bottom has no overflow-anchor-suppressed-at-scrollTop 0 pin like the top, so these are a stick-to-bottom gate + continuation, not an anchor restore.

Verify

Scroll up to evict the tail, PageDown back down: position is preserved as newer batches append, loading continues to the true bottom, and it snaps only at the actual newest.

…bottom

Mirror of the top-edge fix, for the forward (newer) direction. The forward
prefetch is scroll-event driven, so a fast scroll (e.g. PageDown) that reaches
the hard bottom before the network responds won't re-fire once the user stops
there, and newer batches stall. After a forward load that ADDED rows, re-check
post-render (raf): if still within the prefetch band of the new bottom and the
chat end isn't reached, chain the next forward load. Bounded — each append pushes
the bottom ~one batch further, so it stops once ~2 viewports are buffered, at the
chat end, or when the user scrolls away.

The raf is epoch-guarded (drops after a window reset / by-orderId jump), gated on
real progress (a no-progress page can't spin), and cancelled on unmount via
chainRafRef (the #page container outlives the chat). The bottom has no
overflow-anchor pin like scrollTop 0, so this is a continuation, not an anchor
restore.
…l position)

scrollToBottomCheck (stick-to-bottom, for the live tail) fired whenever
isBottom.current was true. During forward pagination (loading newer batches after
the tail was evicted, isAtChatEnd=false), onScroll re-sets isBottom=true while the
user sits at the loaded bottom, so each appended batch snapped the view to the
batch end — dumping the user at the bottom with nothing below to scroll into, so
loading couldn't continue.

Gate the stick-to-bottom on isAtChatEnd: only follow the bottom when actually at
the chat's newest. During pagination the appended rows now sit below the current
position (default append-below keeps scrollTop), so the view stays put and the
user scrolls down through them to load the next page; reaching the true newest
(reachedEdge -> setAtChatEnd) still snaps to the bottom.
@requilence
requilence merged commit 9907827 into develop Jul 4, 2026
3 checks passed
@github-actions github-actions Bot locked and limited conversation to collaborators Jul 4, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant