React Router предоставляет удобные средства для организации навигации в одностраничных приложениях (SPA), включая управление скроллом при переходах к определённым разделам страницы. Работа со скроллом к якорям требует понимания как маршрутизации, так и управления поведением окна браузера.
В React Router поддерживаются ссылки с хэшами (#).
Например, ссылка на элемент с идентификатором section1
может выглядеть так:
import { Link } from 'react-router-dom';
<Link to="#section1">Перейти к разделу 1</Link>
Однако стандартное поведение браузера в SPA часто не срабатывает автоматически из-за того, что React Router предотвращает полное обновление страницы. Для корректного скролла необходимо вручную обрабатывать хэш.
useLocation для отслеживания хэшаReact Router предоставляет хук useLocation, который
возвращает объект с текущим URL, включая pathname и
hash. С его помощью можно отслеживать изменения хэша и
инициировать скролл:
import { useEffect } from 'react';
import { useLocation } from 'react-router-dom';
function ScrollToHash() {
const { hash } = useLocation();
useEffect(() => {
if (hash) {
const element = document.querySelector(hash);
if (element) {
element.scrollIntoView({ beh * avior: 'smooth' });
}
}
}, [hash]);
return null;
}
В этом примере компонент ScrollToHash можно разместить в
верхнем уровне приложения, чтобы он реагировал на изменения URL и плавно
прокручивал страницу к нужному элементу.
Иногда требуется учитывать фиксированные шапки или другие элементы,
перекрывающие якорь. Для этого можно использовать
getBoundingClientRect и прокрутку через
window.scrollTo:
function scrollToElementWithOffset(element, offset = 0) {
const top = element.getBoundingClientRect().top + window.scrollY - offset;
window.scrollTo({ top, beh * avior: 'smooth' });
}
useEffect(() => {
if (hash) {
const element = document.querySelector(hash);
if (element) {
scrollToElementWithOffset(element, 80); // 80px для фиксированной шапки
}
}
}, [hash]);
Такой подход даёт полный контроль над позицией элемента на экране после навигации.
useNavigateПри программной навигации через useNavigate можно сразу
передавать хэш:
import { useNavigate } from 'react-router-dom';
const navigate = useNavigate();
navigate('/page#section2');
Компонент, который отслеживает хэш через useLocation,
автоматически выполнит скролл к указанному элементу.
Для поддержки кнопок «назад» и «вперед» важно сохранять корректное
состояние скролла. React Router не сбрасывает позицию автоматически при
изменении хэша, поэтому можно комбинировать хук
useLayoutEffect с scrollIntoView:
import { useLayoutEffect } from 'react';
useLayoutEffect(() => {
if (hash) {
const element = document.querySelector(hash);
if (element) {
element.scrollIntoView();
}
}
}, [hash]);
useLayoutEffect гарантирует, что прокрутка произойдёт до
того, как браузер визуализирует изменения, предотвращая «дергание»
страницы.
Если элементы якорей создаются динамически (например, после загрузки данных через API), необходимо убедиться, что скролл выполняется после того, как элемент появился в DOM:
useEffect(() => {
const timer = setTimeout(() => {
if (hash) {
const element = document.querySelector(hash);
if (element) {
element.scrollIntoView({ beh * avior: 'smooth' });
}
}
}, 100); // небольшая задержка для загрузки контента
return () => clearTimeout(timer);
}, [hash]);
Более надёжный способ — интеграция с состоянием загрузки контента, чтобы скролл выполнялся только после рендера элементов.
Для сложных интерфейсов можно применять специализированные
библиотеки, такие как react-scroll или
react-router-hash-link, которые абстрагируют обработку
якорей и плавную прокрутку, включая offset и задержку на динамический
контент:
import { HashLink } from 'react-router-hash-link';
<HashLink smooth to="/page#section3">
Перейти к разделу 3
</HashLink>
Такой подход уменьшает количество собственного кода и обеспечивает кросс-браузерную поддержку плавной прокрутки.
#) в URL позволяют идентифицировать элементы
страницы.useLocation — основной инструмент для отслеживания
изменений хэша.scrollIntoView и window.scrollTo с offset
обеспечивают точную прокрутку.Правильная комбинация этих методов позволяет создавать плавную и предсказуемую навигацию в React SPA с поддержкой якорей.