Назад
Frontend

SPA Routing

SPA Routing - это когда навигация по приложению происходит полностью внутри браузера, без запросов на сервер за новой HTML-страницей при каждом клике.

Как это работает

  1. Сервер при первом запросе отдаёт один-единственный index.html
    В нём - <div id="root"></div> и ссылка на огромный js-бандл

  2. JavaScript загружается и сразу читает текущий адрес:
    window.location.pathname > /profile/settings

  3. На основании пути роутер решает, какой компонент показать(чаще всего это дерево маршрутов)

  4. При клике по ссылке происходит примерно следующее:

function handleClick(e) {
  e.preventDefault();           // ← самое важное
  const path = e.currentTarget.getAttribute("href");
  window.history.pushState({}, "", path);  // меняем URL
  // дальше либо setState, либо подписка на popstate / событие роутера
  // → приложение перерисовывает нужный кусок
}
  1. Браузерная кнопка «назад» вызывает событие popstate > роутер снова читает location.pathname и перерисовывает экран

Именно поэтому в хорошем SPA при нажатии «назад» всё выглядит плавно и состояние восстанавливается.

Что использовать для настройки?

  • React Router - классика для реакт приложений
  • Next.js App Router - когда нужен и SSR, и клиентский роутинг, и file-based routing
  • Vue Router, SvelteKit routing, SolidStart, Astro + view transitions - для каждого фреймворка свой раутер

С какими проблемами можно столкнуться?

  1. Сервер не знает про клиентские маршруты
    > заходишь по прямой ссылке /users/948302 > 404
    Решение: на сервере (nginx / express / vercel / netlify) настроить, чтобы любой нестатический путь возвращал 404page

  2. Потеря состояния при рефреше
    > был открыт аккордеон, выбран фильтр, прокручена страница > F5 > всё слетело
    Решение: сохранять в URL (search params), localStorage, IndexedDB или в глобальном состоянии с персистенсом

  3. Дублирующиеся запросы при «назад» / «вперёд»
    > нажал назад > опять полетел запрос за теми же данными
    Решение: кэширование (React Query, SWR, TanStack Query, next/cache)

  4. Scroll restoration ломается
    > после возврата назад страница не прокручивается туда, где была
    Решение: вручную сохранять scroll position или использовать window.history.scrollRestoration = "manual"

  5. Бесконечные редиректы / зацикливание
    > ProtectedRoute > Login > back to protected > redirect loop
    Часто из-за неправильной проверки isAuthenticated в сочетании с useEffect

Безопасность

Клиентский роутинг не даёт никакой защиты - это чисто UX-механизм. Всё, что происходит на фронте, пользователь может изменить.

Самые опасные ловушки:

  • Фейковые route guards на клиенте
   if (localStorage.getItem("role") !== "admin") {
    navigate("/no-access");
  }
    // любой в devtools меняет localStorage и заходит куда угодно  

Решение: Используйте «безопасные данные» или проверки на беке. Проверка должна производиться только с данными из стейта, которые нельзя поменять

  • Открытые данные в бандле
    Весь код SPA скачивается пользователю. Часто в нём лежит:
    • структура всех роутов (включая админские)
    • endpoint’ы API
    • иногда даже чувствительная логика или тестовые токены😁

Решение: code splitting + server-side role-based chunk loading (очень редко реализуют)

  • Манипуляция URL и history API
    Злоумышленник может подменить pathname вручную > если данные грузятся по пути без проверки на бэке > утечка данных

Routing это не просто смена компонентов по путям, но также:

  • синхронизации URL и стейта
  • предзагрузка данных
  • управление скроллом
  • обработка ошибок и fallback’ов
  • кэширование
  • красивые переходы
  • валидации переходов

Чтож, если есть какие-то интересные кейсы, то пишите в комменты 💬