fix(ui): stabilize infinite-stream callbacks + suppress empty-state flash

- useInfiniteStream: wrap fetchNextPage and refresh in useCallback so
  InfiniteScrollArea's IntersectionObserver does not re-subscribe on
  every parent render.
- InfiniteScrollArea: do not render 'End of stream' until at least one
  item has loaded and the initial query has settled (was flashing on
  mount before first fetch).
- AgentHealth: pass isLoading + hasItems to both InfiniteScrollArea
  wrappers.
This commit is contained in:
hsiegeln
2026-04-17 12:52:39 +02:00
parent fb7d6db375
commit 7f233460aa
3 changed files with 22 additions and 6 deletions

View File

@@ -1,5 +1,5 @@
import { useInfiniteQuery, useQueryClient } from '@tanstack/react-query';
import { useMemo } from 'react';
import { useCallback, useMemo } from 'react';
export interface StreamPage<T> {
data: T[];
@@ -52,14 +52,20 @@ export function useInfiniteStream<T>(args: UseInfiniteStreamArgs<T>): UseInfinit
[query.data],
);
const fetchNextPage = useCallback(() => {
if (query.hasNextPage && !query.isFetchingNextPage) query.fetchNextPage();
}, [query.hasNextPage, query.isFetchingNextPage, query.fetchNextPage]);
const refresh = useCallback(() => {
queryClient.invalidateQueries({ queryKey: [...queryKey] });
}, [queryClient, queryKey]);
return {
items,
fetchNextPage: () => {
if (query.hasNextPage && !query.isFetchingNextPage) query.fetchNextPage();
},
fetchNextPage,
hasNextPage: !!query.hasNextPage,
isFetchingNextPage: query.isFetchingNextPage,
isLoading: query.isLoading,
refresh: () => queryClient.invalidateQueries({ queryKey: [...queryKey] }),
refresh,
};
}