Управление скроллом

TanStack Router предоставляет гибкий механизм управления скроллом при навигации, что особенно важно для сложных приложений с динамическим контентом. Управление скроллом позволяет контролировать поведение страницы при переходах между маршрутами, восстанавливать позиции прокрутки и создавать пользовательский опыт, аналогичный нативным приложениям.

Встроенный механизм восстановления позиции

По умолчанию TanStack Router хранит позиции скролла для каждой посещённой страницы. Это реализуется через объект scrollRestoration в конфигурации роутера. Например:

import { createRouter, Route } from '@tanstack/router'

const router = createRouter({
  routes: [
    new Route({ path: '/', component: HomePage }),
    new Route({ path: '/about', component: AboutPage }),
  ],
  scrollRestoration: 'auto',
})

Ключевые значения для scrollRestoration:

  • 'auto' — браузер самостоятельно управляет позицией скролла.
  • 'manual' — необходимо явно управлять прокруткой через события роутера.

Использование 'manual' особенно полезно для сложных страниц с динамическим контентом, где требуется точно контролировать, куда прокрутить пользователя после загрузки нового маршрута.

Пользовательская функция управления скроллом

Для полного контроля над скроллом можно использовать опцию onScrollChange. Она позволяет задавать логику прокрутки при каждом переходе между маршрутами:

const router = createRouter({
  routes,
  onScrollChange: ({ from, to }) => {
    if (to.path === '/about') {
      window.scrollTo({ top: 0, beh * avior: 'smooth' })
    } else if (from.path === '/about') {
      // Сохраняем текущую позицию скролла для возврата
      sessionStorage.setItem('scrollPos', window.scrollY)
    }
  },
})

Особенности onScrollChange:

  • Аргументы from и to содержат информацию о предыдущем и новом маршрутах.
  • Можно реализовать анимацию скролла через beh * avior: 'smooth'.
  • Возможна интеграция с sessionStorage или localStorage для сохранения и восстановления позиций при навигации назад и вперед.

Асинхронная прокрутка и загрузка данных

TanStack Router поддерживает асинхронное управление скроллом. Это важно, когда компонент загружается динамически или требует данных с сервера:

const router = createRouter({
  routes,
  onScrollChange: async ({ to }) => {
    if (to.path === '/posts/:id') {
      await fetchPostData(to.params.id)
      const targetElement = document.getElementById('post-content')
      targetElement.scrollIntoView({ beh * avior: 'smooth' })
    }
  },
})

Преимущества асинхронного подхода:

  • Прокрутка происходит только после загрузки данных.
  • Предотвращает “прыжки” страницы при динамическом рендеринге контента.
  • Можно реализовать плавное скроллирование к определённым элементам на странице.

Сохранение и восстановление позиции при возврате

Для сложных приложений с табами и длинными списками часто необходимо сохранять позицию скролла при возврате на предыдущую страницу. TanStack Router позволяет реализовать это с помощью состояния маршрута:

const router = createRouter({
  routes,
  onScrollChange: ({ from, to }) => {
    if (from) {
      from.meta.scrollY = window.scrollY
    }
    if (to.meta.scrollY !== undefined) {
      window.scrollTo({ top: to.meta.scrollY, beh * avior: 'auto' })
    }
  },
})

Особенности этого подхода:

  • Позиция скролла сохраняется в метаданных маршрута (meta).
  • При возврате к предыдущему маршруту позиция восстанавливается мгновенно или с анимацией.
  • Совместимо с вложенными маршрутами и динамическими страницами.

Интеграция с библиотеками виртуализации

При работе с длинными списками или таблицами часто используется виртуализация через react-virtual или аналогичные решения. В этом случае стандартный window.scrollTo не работает напрямую, и нужно управлять прокруткой контейнера виртуализированного списка:

const router = createRouter({
  routes,
  onScrollChange: ({ to }) => {
    const listContainer = document.getElementById('virtual-list')
    if (listContainer && to.meta.scrollPos) {
      listContainer.scrollTop = to.meta.scrollPos
    }
  },
})

Важно:

  • Следует сохранять позиции скролла контейнера, а не окна.
  • Такой подход позволяет реализовать точное восстановление позиции для больших списков с динамическим контентом.

Настройка поведения прокрутки для вложенных маршрутов

TanStack Router поддерживает вложенные маршруты, и для каждого из них можно задавать отдельную логику скролла:

const router = createRouter({
  routes: [
    new Route({
      path: '/dashboard',
      children: [
        new Route({
          path: 'analytics',
          component: AnalyticsPage,
          onScrollChange: () => window.scrollTo({ top: 100 }),
        }),
        new Route({
          path: 'reports',
          component: ReportsPage,
          onScrollChange: () => window.scrollTo({ top: 0 }),
        }),
      ],
    }),
  ],
})

Особенности:

  • Вложенные маршруты могут переопределять глобальное поведение прокрутки.
  • Можно комбинировать автоматическое и пользовательское управление скроллом.
  • Поддерживается плавная анимация и восстановление позиций при навигации между вкладками.