Чтение query-параметров

React Router предоставляет мощные средства для организации маршрутизации в приложениях на React. Одним из часто встречающихся требований является работа с query-параметрами — частью URL, которая начинается с ? и передаёт дополнительные данные на страницу.

Основы query-параметров

Query-параметры находятся после символа ? в URL и имеют вид:

/products?category=books&sort=price

Здесь ключами являются category и sort, а значениями — books и price соответственно. React Router сам по себе не предоставляет отдельного API для работы с query-параметрами, поэтому для их чтения чаще всего используют стандартный объект URLSearchParams из браузера.

Использование useLocation для доступа к query-параметрам

Для получения текущего URL в функциональных компонентах используется хук useLocation:

import { useLocation } from 'react-router-dom';

function ProductsPage() {
  const location = useLocation();
  const searchParams = new URLSearchParams(location.search);

  const category = searchParams.get('category');
  const sort = searchParams.get('sort');

  return (
    <div>
      <h1>Products</h1>
      <p>Категория: {category}</p>
      <p>Сортировка: {sort}</p>
    </div>
  );
}
  • useLocation возвращает объект с текущим URL, включая pathname и search.
  • location.search содержит строку query-параметров (например, ?category=books&sort=price).
  • URLSearchParams позволяет получить значения конкретных параметров через метод .get().

Чтение нескольких значений одного параметра

Query-параметр может повторяться несколько раз в URL:

/products?tag=fiction&tag=bestseller

Чтобы получить все значения tag, используется метод .getAll():

const tags = searchParams.getAll('tag'); // ['fiction', 'bestseller']

Это особенно полезно для фильтров и тегов, которые могут быть множественными.

Динамическое реагирование на изменения query-параметров

Если требуется, чтобы компонент реагировал на изменения query-параметров без перезагрузки страницы, стоит использовать useEffect вместе с useLocation:

import { useEffect } from 'react';

useEffect(() => {
  const searchParams = new URLSearchParams(location.search);
  const category = searchParams.get('category');
  // выполнение логики при изменении query-параметра
}, [location.search]);

Здесь location.search выступает зависимостью эффекта, обеспечивая вызов функции при каждом изменении query-параметров.

Создание query-параметров для переходов

Для генерации ссылок с query-параметрами удобно использовать объект URLSearchParams или библиотеку query-string для сериализации:

import { Link } from 'react-router-dom';

const params = new URLSearchParams({ category: 'books', sort: 'price' });

<Link to={`/products?${params.toString()}`}>Сортировка по цене</Link>
  • Метод .toString() преобразует объект URLSearchParams в корректную строку для URL.
  • Такой подход позволяет избежать ручного конкатенирования строк, что уменьшает вероятность ошибок.

Обработка параметров при программной навигации

При использовании хука useNavigate query-параметры также можно передавать через строку:

import { useNavigate } from 'react-router-dom';

const navigate = useNavigate();

function handleSortChange(sortValue) {
  const params = new URLSearchParams({ sort: sortValue });
  navigate(`/products?${params.toString()}`);
}

Это гарантирует, что навигация будет корректно учитывать query-параметры и браузерная история сохранит переходы.

Парсинг числовых и логических значений

Query-параметры приходят как строки. Для работы с числами или булевыми значениями требуется явное преобразование:

const page = Number(searchParams.get('page')) || 1;
const showFeatured = searchParams.get('featured') === 'true';
  • Number() преобразует строку в число, возвращая NaN для некорректных значений.
  • Сравнение с 'true' или 'false' позволяет корректно получать булевое значение.

Работа с несколькими параметрами через кастомный хук

Для упрощения работы с query-параметрами часто создают собственный хук:

import { useLocation } from 'react-router-dom';
import { useMemo } from 'react';

function useQuery() {
  const { search } = useLocation();

  return useMemo(() => new URLSearchParams(search), [search]);
}

// Использование
const query = useQuery();
const category = query.get('category');
const sort = query.get('sort');

Преимущество — чистый синтаксис и мемоизация, которая предотвращает лишние пересоздания объекта URLSearchParams при каждом рендере.

Интеграция с состоянием компонентов

Для динамических фильтров часто удобно синхронизировать query-параметры с состоянием React:

const [category, setCategory] = useState(query.get('category') || '');

useEffect(() => {
  const params = new URLSearchParams();
  if (category) params.set('category', category);
  navigate(`/products?${params.toString()}`, { replace: true });
}, [category]);
  • replace: true обновляет текущий URL без добавления новой записи в историю.
  • Это позволяет поддерживать фильтры и сортировки в URL, сохраняя возможность делиться ссылкой.

Особенности и подводные камни

  • URLSearchParams чувствителен к кодировке. Для безопасного использования лучше использовать методы encodeURIComponent и decodeURIComponent, если есть нестандартные символы.
  • Порядок query-параметров не влияет на их значение, но может быть важен при сравнении URL.
  • При большом числе параметров рекомендуется использовать утилиты типа query-string, которые обеспечивают сериализацию массивов и вложенных объектов.

React Router в сочетании с URLSearchParams обеспечивает гибкую и безопасную работу с query-параметрами, позволяя создавать динамические, легко навигируемые интерфейсы.