Сложные параметры поиска

TanStack Router предоставляет мощный и гибкий способ управления маршрутами в приложениях на JavaScript и TypeScript. Одной из ключевых возможностей является работа со сложными параметрами поиска (query parameters), которые выходят за рамки простых строк или чисел и позволяют передавать структурированные данные, фильтры, массивы и объекты.


1. Определение и типизация параметров поиска

Для работы с параметрами поиска в TanStack Router используются объекты типа searchSchema, которые позволяют строго типизировать данные, проходящие через URL. В отличие от стандартных строковых параметров, query-параметры можно представить как объект с заранее определёнными полями.

import { createRouter, Route } from '@tanstack/router';
import { z } from 'zod';

const searchSchema = z.object({
  filter: z.string().optional(),
  page: z.number().default(1),
  tags: z.array(z.string()).optional(),
});

const route = new Route({
  path: '/items',
  searchSchema,
});

В этом примере:

  • filter — строковый фильтр, может отсутствовать;
  • page — числовой параметр с дефолтным значением 1;
  • tags — массив строк, необязательный.

Использование zod позволяет не только проверять тип данных, но и автоматически приводить их к нужным типам при чтении из URL.


2. Работа с массивами и объектами

TanStack Router позволяет передавать сложные структуры, такие как массивы и объекты, через параметры поиска. Для массивов рекомендуется использовать стандартную сериализацию через [], а для объектов — JSON-сериализацию.

const route = new Route({
  path: '/search',
  searchSchema: z.object({
    categories: z.array(z.string()).optional(),
    filters: z.string().transform(JSON.parse).optional(),
  }),
});

// Пример URL:
// /search?categories[]=books&categories[]=electronics&filters={"priceRange":[10,100]}

При таком подходе:

  • categories[] автоматически преобразуется в массив;
  • filters хранится как JSON-строка и при загрузке страницы десериализуется в объект.

Важно правильно обрабатывать сериализацию и десериализацию, чтобы избежать ошибок при работе с объектами сложной структуры.


3. Изменение параметров поиска

Для обновления query-параметров используется метод router.navigate, который позволяет изменять только нужные параметры, не ломая остальные.

router.navigate({
  to: '/items',
  search: prev => ({
    ...prev,
    page: 2,
    tags: ['new', 'popular'],
  }),
});

Ключевые моменты:

  • Сохраняются предыдущие параметры (...prev).
  • Можно изменять массивы и объекты, передавая новые значения.
  • TanStack Router корректно обновляет URL без полной перезагрузки страницы.

4. Композиция параметров с маршрутами

Сложные query-параметры легко комбинировать с динамическими сегментами маршрута. Например, можно иметь маршрут /users/:userId/items и одновременно управлять фильтрами через параметры поиска.

const userItemsRoute = new Route({
  path: '/users/:userId/items',
  searchSchema: z.object({
    sortBy: z.enum(['name', 'date']).default('name'),
    tags: z.array(z.string()).optional(),
  }),
});

Использование таких маршрутов позволяет:

  • Разделять логику сегментов URL и параметров поиска.
  • Поддерживать сложные фильтры на уровне компонента, не ломая структуру маршрута.

5. Роутинг и синхронизация состояния с UI

Для реактивного UI удобно использовать хуки, которые TanStack Router предоставляет для query-параметров:

const [searchParams, setSearchParams] = useSearchParams(userItemsRoute);

setSearchParams(prev => ({
  ...prev,
  sortBy: 'date',
  tags: [...(prev.tags || []), 'featured'],
}));

Преимущества такого подхода:

  • Параметры поиска автоматически синхронизируются с URL.
  • Состояние компонентов и URL остаются согласованными.
  • Можно легко реагировать на изменения параметров с помощью эффектов.

6. Советы по работе с большими query-объектами

  1. Минимизировать размер URL — большие JSON-объекты следует кодировать и декодировать через encodeURIComponent/decodeURIComponent.
  2. Использовать дефолтные значения — это упрощает работу с необязательными полями и предотвращает появление undefined в URL.
  3. Типизация через zod или superstruct — обеспечивает безопасность данных и удобство автокомплита.
  4. Избегать вложенных объектов слишком глубоко — сложные структуры лучше хранить в состоянии приложения и передавать только идентификаторы или ключи в query.