fix(site): fix agents sidebar not loading all pages when sentinel stays visible (#23613)

This commit is contained in:
Danielle Maywood
2026-03-25 16:40:26 +00:00
committed by GitHub
parent 9d0945fda7
commit 110af9e834
2 changed files with 58 additions and 12 deletions
@@ -258,6 +258,50 @@ describe("AgentsSidebar load-more behavior", () => {
expect(onLoadMore).toHaveBeenCalledTimes(1);
});
it("recreates the observer when isFetchingNextPage transitions to false so visible sentinels re-trigger", () => {
const onLoadMore = vi.fn();
const { rerender } = render(
<Wrapper>
<AgentsSidebar
{...defaultProps}
hasNextPage
onLoadMore={onLoadMore}
isFetchingNextPage={false}
/>
</Wrapper>,
);
const countAfterMount = observeCount;
expect(countAfterMount).toBe(1);
// Start fetching — observer is torn down.
rerender(
<Wrapper>
<AgentsSidebar
{...defaultProps}
hasNextPage
onLoadMore={onLoadMore}
isFetchingNextPage={true}
/>
</Wrapper>,
);
// Fetch completes — a fresh observer is created, firing
// an initial entry that detects the still-visible sentinel.
rerender(
<Wrapper>
<AgentsSidebar
{...defaultProps}
hasNextPage
onLoadMore={onLoadMore}
isFetchingNextPage={false}
/>
</Wrapper>,
);
expect(observeCount).toBe(countAfterMount + 1);
});
it("does NOT render the sentinel when hasNextPage is false", () => {
const onLoadMore = vi.fn();
render(
@@ -1131,27 +1131,29 @@ const LoadMoreSentinel: FC<{
}> = ({ onLoadMore, isFetchingNextPage }) => {
const sentinelRef = useRef<HTMLDivElement>(null);
const onLoadMoreRef = useRef(onLoadMore);
const isFetchingNextPageRef = useRef(isFetchingNextPage);
// Keep refs in sync with the latest prop values so the
// observer callback always reads current state without
// needing to tear down and re-create the observer.
// Keep the callback ref in sync so the observer closure
// always calls the latest onLoadMore without needing to
// tear down and re-create the observer.
useEffect(() => {
onLoadMoreRef.current = onLoadMore;
isFetchingNextPageRef.current = isFetchingNextPage;
}, [onLoadMore, isFetchingNextPage]);
}, [onLoadMore]);
useEffect(() => {
// Don't observe while a fetch is in progress. When the
// fetch completes this effect re-runs, creating a fresh
// observer whose initial entry detects the sentinel if
// it's still visible — fixing the case where loaded items
// don't push the sentinel out of view and the previous
// observer never re-fires.
if (isFetchingNextPage) return;
const el = sentinelRef.current;
if (!el) return;
const observer = new IntersectionObserver(
(entries) => {
if (
entries[0]?.isIntersecting &&
!isFetchingNextPageRef.current &&
onLoadMoreRef.current
) {
if (entries[0]?.isIntersecting && onLoadMoreRef.current) {
onLoadMoreRef.current();
}
},
@@ -1159,7 +1161,7 @@ const LoadMoreSentinel: FC<{
);
observer.observe(el);
return () => observer.disconnect();
}, []);
}, [isFetchingNextPage]);
return (
<div ref={sentinelRef} className="flex items-center justify-center py-2">