Управление состоянием поиска

В TanStack Router управление состоянием поиска (search state) является одной из ключевых возможностей для реализации динамической маршрутизации с сохранением параметров запроса в URL. Поиск позволяет хранить данные в виде пары «ключ–значение» в строке запроса, что делает маршруты более гибкими и удобными для работы с фильтрами, пагинацией, сортировкой и другими параметрами пользовательского интерфейса.

Основы search state

Search state — это объект, который хранит параметры поиска, доступные в текущем маршруте. TanStack Router предоставляет встроенные механизмы для чтения и изменения этих параметров без перезагрузки страницы, что упрощает управление состоянием приложения.

Пример базовой конфигурации маршрута с search state:

import { createRouter, createRouteConfig } from '@tanstack/router';

const rootRoute = createRouteConfig()
  .route({
    path: '/',
    component: HomePage,
  });

const router = createRouter({
  routeConfig: rootRoute,
  defaultSearch: {
    page: 1,
    filter: ''
  }
});

В этом примере defaultSearch задаёт начальные значения параметров поиска. Если URL не содержит соответствующих параметров, будут использованы эти значения по умолчанию.

Чтение и запись параметров поиска

Для работы с search state в компоненте используется хук useSearch. Он возвращает объект текущих параметров и функцию для их обновления:

import { useSearch } from '@tanstack/router';

function HomePage() {
  const [search, setSearch] = useSearch();

  const handleFilterChange = (value) => {
    setSearch({ ...search, filter: value });
  };

  return (
    <div>
      <input
        type="text"
        value={search.filter || ''}
        onCha nge={(e) => handleFilterChange(e.target.value)}
      />
      <p>Текущий фильтр: {search.filter}</p>
    </div>
  );
}

Здесь ключевой момент — обновление состояния поиска происходит через setSearch, что автоматически синхронизирует URL с параметрами поиска. Это обеспечивает возможность прямого копирования ссылки с фильтром или пагинацией.

Управление типами параметров

TanStack Router позволяет явно задавать типы параметров поиска, что повышает безопасность и удобство использования. Для этого используется опция searchSchema при создании маршрута:

const route = rootRoute.route({
  path: '/products',
  component: ProductsPage,
  searchSchema: {
    page: { type: 'number', default: 1 },
    filter: { type: 'string', default: '' }
  }
});

При этом библиотека автоматически выполняет приведение типов и подставляет значения по умолчанию, если параметр отсутствует или некорректен.

Обновление search state без перезагрузки

Одним из ключевых преимуществ TanStack Router является возможность обновления параметров поиска без перезагрузки компонента. Для этого используются функции setSearch или router.navigate с указанием search:

router.navigate({
  to: route.id,
  search: { page: 2, filter: 'shoes' }
});

При этом текущий компонент не будет размонтирован, а изменения будут отражены сразу в UI.

Поддержка мемоизации и зависимостей

Чтобы оптимизировать работу компонентов, использующих search state, рекомендуется использовать мемоизацию значений и вычисляемые свойства на основе search:

import { useMemo } from 'react';
import { useSearch } from '@tanstack/router';

function FilteredList() {
  const [search] = useSearch();

  const filteredItems = useMemo(() => {
    return items.filter(item => item.name.includes(search.filter || ''));
  }, [search.filter]);

  return (
    <ul>
      {filteredItems.map(item => (
        <li key={item.id}>{item.name}</li>
      ))}
    </ul>
  );
}

Использование useMemo предотвращает лишние пересчёты при изменении других параметров, что критично для производительных интерфейсов с большим количеством элементов.

Поддержка вложенных маршрутов

В TanStack Router search state может быть локальным для конкретного маршрута или наследоваться от родительских маршрутов. Это позволяет строить сложные иерархии с фильтрацией на разных уровнях:

const productsRoute = rootRoute.route({
  path: 'products',
  component: ProductsPage,
  searchSchema: {
    category: { type: 'string' }
  },
  children: (route) => [
    route.route({
      path: 'details/:id',
      component: ProductDetailsPage,
      searchSchema: {
        showReviews: { type: 'boolean', default: true }
      }
    })
  ]
});

В этом примере маршрут ProductDetailsPage наследует часть состояния поиска от родительского маршрута, при этом добавляя собственные параметры.

Практические рекомендации

  • Всегда определять searchSchema для параметров поиска, чтобы избежать неожиданных значений.
  • Использовать setSearch для обновления параметров, чтобы сохранялась синхронизация с URL.
  • При больших списках данных фильтровать и сортировать элементы через мемоизированные вычисления.
  • Для вложенных маршрутов разделять параметры поиска на глобальные и локальные, чтобы избежать конфликтов.

Эффективное использование search state в TanStack Router позволяет создавать маршруты, полностью управляемые через URL, сохраняя при этом интерактивность и отзывчивость интерфейса. Это особенно важно для приложений с динамическими списками, фильтрацией и пагинацией, где каждый параметр поиска должен быть доступен напрямую через ссылку.