Я использую:
- для виртуализации
Код: Выделить всё
@tanstack/react-virtual - из @tanstack/react-query для загрузки сообщений
Код: Выделить всё
useInfiniteQuery
- Когда пользователь прокручивает страницу вверх, я получаю предыдущую страницу сообщений
- Новые сообщения добавляются в начале правильно
- Но я хочу, чтобы положение прокрутки оставалось стабильным, чтобы пользователь не чувствовал «прыжка»
Код: Выделить всё
// Scroll detection for infinite loading at top
const fetchMoreOnTopReached = useCallback(
(containerRefElement?: HTMLDivElement | null) => {
if (!onScrollToTop || isFetchingMore || !containerRefElement) return;
// Check if we've reached the top threshold
if (
isScrollThresholdReached({
container: containerRefElement,
direction: ScrollDirection.TOP,
threshold: SCROLL_THRESHOLD_PX,
})
) {
// ✅ Take snapshot RIGHT HERE before triggering the fetch
previousScrollPositionFromBottomRef.current =
getScrollPositionFromBottom();
console.log("📸 Snapshot taken at threshold:", {
scrollHeight: containerRefElement.scrollHeight,
positionFromBottom: previousScrollPositionFromBottomRef.current,
});
onScrollToTop();
}
},
[onScrollToTop, isFetchingMore]
);
const getScrollPositionFromBottom = useCallback(() => {
const container = scrollContainerRef.current;
if (!container) return 0;
const { scrollTop, scrollHeight, clientHeight } = container;
return scrollHeight - scrollTop - clientHeight;
}, [scrollContainerRef]);
// Debug logging to inspect scroll behavior
useEffect(() => {
setInterval(() => {
const container = scrollContainerRef.current;
if (!container) return;
console.log("🔄 Scroll height:", container.scrollHeight);
console.log("🔄 Scroll position from bottom:", getScrollPositionFromBottom());
}, 1000);
}, [scrollContainerRef, getScrollPositionFromBottom]);
// Restore scroll position after messages are prepended
useLayoutEffect(() => {
const container = scrollContainerRef.current;
if (!container) return;
if (
isFetchingMore === false &&
previousScrollPositionFromBottomRef.current > 0
) {
const { scrollHeight, clientHeight } = container;
console.log("🔄 Restoring scroll height:", scrollHeight);
const newScrollTop =
scrollHeight -
previousScrollPositionFromBottomRef.current -
clientHeight;
console.log("🔄 Restoring scroll position:", {
newScrollTop,
positionFromBottom: previousScrollPositionFromBottomRef.current,
});
// Wait for the virtualizer to re-measure
requestAnimationFrame(() => {
requestAnimationFrame(() => {
virtualizer.scrollToOffset(newScrollTop, {
align: "start",
behavior: "auto",
});
});
});
// Reset ref
previousScrollPositionFromBottomRef.current = 0;
}
}, [isFetchingMore, getScrollPositionFromBottom, virtualizer]);
Кто-нибудь нашел способ обработать "бесконечную прокрутку сверху" с помощью TanStack Virtual, сохраняя при этом положение прокрутки стабильно?
Любые примеры кода, стратегии синхронизации или вспомогательные утилиты/библиотеки, которые упростят эту задачу, были бы замечательными.
Подробнее здесь: https://stackoverflow.com/questions/797 ... ack-virtua