Прокрутка и восстановление позиции
При переходе между страницами браузер по умолчанию сохраняет позицию скролла. В SPA это часто не то, что нужно.
Проблема
Пользователь на длинной странице прокрутил вниз. Кликнул по ссылке на другую страницу. Новая страница открывается на той же позиции скролла — обычно внизу. Ожидание — открыться сверху.
ScrollToTop
Компонент, который сбрасывает скролл при смене маршрута:
import { useEffect } from 'react';
import { useLocation } from 'react-router-dom';
function ScrollToTop() {
const { pathname } = useLocation();
useEffect(() => {
window.scrollTo(0, 0);
}, [pathname]);
return null;
}
Разместить внутри BrowserRouter, но вне Routes:
<BrowserRouter>
<ScrollToTop />
<App />
</BrowserRouter>
Восстановление позиции
Когда пользователь нажимает «Назад» — хочется вернуться на ту же позицию. Для этого сохраняй позицию в sessionStorage:
function ScrollRestoration() {
const location = useLocation();
const navigationType = useNavigationType();
useEffect(() => {
const key = `scroll:${location.key}`;
if (navigationType === 'POP') {
const saved = sessionStorage.getItem(key);
if (saved) {
window.scrollTo(0, Number(saved));
return;
}
}
window.scrollTo(0, 0);
}, [location, navigationType]);
useEffect(() => {
function save() {
sessionStorage.setItem(`scroll:${location.key}`, String(window.scrollY));
}
window.addEventListener('scroll', save, { passive: true });
return () => window.removeEventListener('scroll', save);
}, [location]);
return null;
}
useNavigationType возвращает PUSH, POP или REPLACE.
Прокрутка к элементу
Если нужно прокрутить к якорю:
function ScrollToHash() {
const { hash } = useLocation();
useEffect(() => {
if (hash) {
const el = document.querySelector(hash);
el?.scrollIntoView({ behavior: 'smooth' });
}
}, [hash]);
return null;
}
Плавная прокрутка
window.scrollTo({ top: 0, behavior: 'smooth' });
Прокрутка внутри контейнера
Если контент прокручивается внутри div (например, модалка или сайдбар):
const containerRef = useRef<HTMLDivElement>(null);
useEffect(() => {
containerRef.current?.scrollTo(0, 0);
}, [pathname]);
Сохранение позиции списка
Для списков с бесконечной прокруткой — сохраняй не только позицию, но и загруженные данные, чтобы не грузить заново.
Итоги
- ScrollToTop — сброс при смене маршрута
- Восстановление — через
sessionStorage useNavigationTypeдля POP/PUSH- Прокрутка к якорю — через
hash - Плавная —
behavior: 'smooth' - Для контейнера —
ref