Синхронизация URL и состояния формы

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

Управление параметрами маршрута

Каждый маршрут в TanStack Router может содержать параметры, которые автоматически синхронизируются с URL. Параметры могут быть обязательными, необязательными, а также иметь дефолтные значения. Для синхронизации состояния формы чаще всего используются query-параметры.

Пример определения маршрута с query-параметрами:

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

const searchRoute = createRoute({
  path: '/search',
  query: {
    query: {
      default: '',
    },
    page: {
      default: 1,
    },
  },
});

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

Связывание формы с состоянием маршрута

Для интеграции формы с TanStack Router применяется хук useSearch, который предоставляет объект с текущими значениями query-параметров и функцию для их обновления.

Пример формы поиска:

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

function SearchForm() {
  const [searchParams, setSearchParams] = useSearch();

  const handleChange = (event) => {
    setSearchParams({ ...searchParams, query: event.target.value, page: 1 });
  };

  return (
    <input
      type="text"
      value={searchParams.query || ''}
      onCha nge={handleChange}
      placeholder="Введите запрос"
    />
  );
}

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

  • Изменение значения input автоматически обновляет URL без перезагрузки страницы.
  • Сброс значения page при изменении запроса обеспечивает корректную навигацию между страницами результатов.

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

TanStack Router использует push и replace для управления историей браузера:

setSearchParams(
  { query: 'tanstack', page: 2 },
  { replace: true } // заменяет текущую запись в истории
);
  • push по умолчанию создаёт новую запись в истории, что позволяет использовать кнопки “назад” и “вперёд”.
  • replace позволяет менять URL без добавления новой записи, что удобно для интерактивных форм.

Валидация и преобразование параметров

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

const [searchParams, setSearchParams] = useSearch();

const page = Number(searchParams.page) || 1;
const showArchived = searchParams.showArchived === 'true';

TanStack Router поддерживает кастомные валидаторы через parser и serializer, что позволяет автоматически конвертировать значения при чтении и записи в URL:

query: {
  page: {
    default: 1,
    parser: (value) => parseInt(value, 10),
    serializer: (value) => String(value),
  },
}

Сложные формы с несколькими полями

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

query: {
  filters: {
    default: {},
  },
}

Пример обновления нескольких фильтров:

setSearchParams({
  filters: {
    category: 'books',
    priceRange: '0-100',
    inStock: true,
  },
});

TanStack Router автоматически сериализует вложенные объекты в URL, используя формат filters[category]=books&filters[priceRange]=0-100.

Отложенное обновление состояния

Чтобы уменьшить количество изменений URL при вводе текста, можно использовать debounce:

import { useEffect, useState } from 'react';
import { useSearch } from '@tanstack/router';
import { debounce } from 'lodash';

function DebouncedSearch() {
  const [searchParams, setSearchParams] = useSearch();
  const [input, setInput] = useState(searchParams.query || '');

  const debouncedUpdate = debounce((value) => {
    setSearchParams({ query: value });
  }, 300);

  useEffect(() => {
    debouncedUpdate(input);
  }, [input]);

  return <input value={input} onCha nge={(e) => setInput(e.target.value)} />;
}

Синхронизация состояния с внешними библиотеками форм

TanStack Router можно интегрировать с react-hook-form или Formik. Для этого состояния формы синхронизируются с query-параметрами при сабмите или изменении полей:

import { useForm } from 'react-hook-form';
import { useSearch } from '@tanstack/router';

function FilterForm() {
  const { register, handleSubmit } = useForm();
  const [, setSearchParams] = useSearch();

  const onSub mit = (data) => {
    setSearchParams({ ...data, page: 1 });
  };

  return (
    <form onSub mit={handleSubmit(onSubmit)}>
      <input {...register('category')} placeholder="Категория" />
      <input type="checkbox" {...register('inStock')} /> В наличии
      <button type="submit">Применить</button>
    </form>
  );
}
  • При сабмите URL обновляется, что позволяет делиться текущими фильтрами.
  • Структура query-параметров соответствует полям формы.

Поддержка навигации назад и вперёд

Синхронизация состояния формы с URL автоматически включает поддержку истории браузера. Любое изменение query-параметров фиксируется как отдельный шаг истории, позволяя пользователю:

  • возвращаться к предыдущему состоянию формы,
  • переходить вперёд без потери данных,
  • использовать закладки для конкретного состояния формы.

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

  • Минимизировать лишние обновления URL, используя debounce или обновления при сабмите.
  • Использовать parser/serializer для числовых и булевых значений, чтобы избежать ошибок при чтении из URL.
  • Сохранять вложенные объекты в query-параметрах, чтобы поддерживать сложные фильтры.
  • Всегда задавать дефолтные значения, чтобы форма корректно инициализировалась при прямом переходе по ссылке.

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