Как сохранить стабильное положение прокрутки при загрузке сообщений сверху (TanStack Virtual и Next.js)?Javascript

Форум по Javascript
Ответить
Anonymous
 Как сохранить стабильное положение прокрутки при загрузке сообщений сверху (TanStack Virtual и Next.js)?

Сообщение Anonymous »

Я создаю пользовательский интерфейс чата в Next.js (App Router) и пытаюсь сохранить положение прокрутки при загрузке старых сообщений вверху.
Я использую: Поведение, которое я хочу
  • Когда пользователь прокручивает страницу вверх, я получаю предыдущую страницу сообщений
  • Новые сообщения добавляются в начале правильно
  • Но я хочу, чтобы положение прокрутки оставалось стабильным, чтобы пользователь не чувствовал «прыжка»
Вот что я пробовал (TypeScript)

Код: Выделить всё

// 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
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Javascript»