TanStack Router предоставляет гибкий механизм управления состоянием прокрутки при навигации между страницами. Одной из ключевых задач фронтенд-разработки является сохранение позиции скролла при возврате на предыдущую страницу, чтобы пользовательский опыт оставался непрерывным и естественным. TanStack Router предлагает Scroll Restoration API, которое позволяет точно управлять этой функциональностью.
По умолчанию браузеры выполняют стандартное поведение восстановления
скролла при переходе по истории (history.back() или
history.forward()). Однако при SPA (Single Page
Application) этот процесс часто нарушается, так как переходы между
“страницами” не сопровождаются полной перезагрузкой документа. TanStack
Router решает эту проблему с помощью встроенного механизма:
Для активации Scroll Restoration необходимо подключить соответствующую опцию при создании маршрутизатора.
import { createRouter, createWebHistory } from '@tanstack/router';
const router = createRouter({
history: createWebHistory(),
defaultOptions: {
restoreScroll: true, // Включение восстановления скролла по умолчанию
},
});
TanStack Router предоставляет несколько стратегий восстановления скролла:
Автоматическое восстановление
restoreScroll: true.Восстановление в верхнюю точку страницы
scrollRestoration на
уровне маршрута:const route = router.createRoute({
path: '/home',
component: HomePage,
options: {
scrollRestoration: () => ({ x: 0, y: 0 }),
},
});
Пользовательская логика восстановления
const route = router.createRoute({
path: '/profile',
component: ProfilePage,
options: {
scrollRestoration: ({ location }) => {
const element = document.getElementById(`section-${location.params.sectionId}`);
return element ? { x: 0, y: element.offsetTop } : { x: 0, y: 0 };
},
},
});
Частая проблема SPA — когда содержимое страницы загружается асинхронно, скролл может восстановиться раньше, чем DOM полностью построен. TanStack Router позволяет управлять этим через промисы:
const route = router.createRoute({
path: '/posts/:postId',
component: PostPage,
loader: async ({ params }) => {
return fetchPost(params.postId);
},
options: {
scrollRestoration: async ({ routeInstance }) => {
await routeInstance.loaderPromise; // Дождаться загрузки данных
const postElement = document.getElementById('post-content');
return postElement ? { x: 0, y: postElement.offsetTop } : { x: 0, y: 0 };
},
},
});
Такой подход гарантирует, что скролл будет восстановлен после полной загрузки контента, что предотвращает “скачок” страницы при переходе.
Для вложенных маршрутов TanStack Router поддерживает наследование и переопределение поведения восстановления скролла. Например, если родительский маршрут должен сбрасывать скролл, а дочерние маршруты — сохранять текущую позицию:
const parentRoute = router.createRoute({
path: '/dashboard',
component: DashboardLayout,
options: { scrollRestoration: () => ({ x: 0, y: 0 }) },
});
const childRoute = parentRoute.createRoute({
path: 'reports',
component: ReportsPage,
options: { scrollRestoration: true }, // Сохранять позицию скролла
});
При больших приложениях важно учитывать, что сохранение позиций скролла для множества маршрутов может потреблять память. TanStack Router использует карточку истории маршрутов, которая хранит только актуальные позиции для последних посещённых страниц. Для расширенного контроля можно реализовать кэширование скролла вручную:
const scrollCache = new Map();
router.subscribe(({ location, action }) => {
if (action === 'PUSH') {
scrollCache.set(location.key, { x: window.scrollX, y: window.scrollY });
}
if (action === 'POP') {
const position = scrollCache.get(location.key) || { x: 0, y: 0 };
window.scrollTo(position.x, position.y);
}
});
Такой подход позволяет управлять положением скролла в любых сценариях, включая кастомные переходы и модальные окна.
restoreScroll: true.