fix(chat): forward pagination — keep position + keep loading (JS-9822)#2279
Merged
Conversation
…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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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
scrollToBottomCheck(stick-to-bottom, meant for the live tail) fires wheneverisBottom.currentis true. During forward paginationonScrollre-setsisBottom=trueat 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.Fixes
isAtChatEnd— only follow the bottom when at the chat's newest. During pagination the appended rows stay below the current position (default append-below keepsscrollTop), so the view stays put and you scroll down through them; reaching the true newest still snaps.#pagecontainer outlives the chat).The bottom has no
overflow-anchor-suppressed-at-scrollTop 0pin 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.