Скролл к якорям

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 и плавно прокручивал страницу к нужному элементу.


Плавная прокрутка и offset

Иногда требуется учитывать фиксированные шапки или другие элементы, перекрывающие якорь. Для этого можно использовать 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 с поддержкой якорей.