Урок 06

Query-параметры

Query-параметры — часть URL после ?. Например, /posts?page=2&sort=date.

useSearchParams

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

function Posts() {
    const [searchParams, setSearchParams] = useSearchParams();

    const page = Number(searchParams.get('page') ?? 1);
    const sort = searchParams.get('sort') ?? 'date';

    return (
        <>
            <p>Страница: {page}</p>
            <p>Сортировка: {sort}</p>
        </>
    );
}

searchParams — объект URLSearchParams.

Методы URLSearchParams

searchParams.get('page');         // '2' или null
searchParams.getAll('tag');       // массив
searchParams.has('page');         // true/false

Изменение

function nextPage() {
    setSearchParams({ page: String(page + 1), sort });
}

С функцией:

setSearchParams((prev) => {
    prev.set('page', String(page + 1));
    return prev;
});

Сброс параметра

setSearchParams((prev) => {
    prev.delete('sort');
    return prev;
});

Массив значений

<Link to="/posts?tag=js&tag=react">Метки</Link>

const tags = searchParams.getAll('tag'); // ['js', 'react']

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

<Link to={{ pathname: '/posts', search: '?page=2' }}>Страница 2</Link>

<Link to={`/posts?page=${page + 1}`}>Дальше</Link>

Фильтры в URL

Хорошая практика: фильтры, сортировка, пагинация — в URL. Тогда ссылкой можно поделиться, работают кнопки назад/вперёд.

function Posts() {
    const [searchParams, setSearchParams] = useSearchParams();

    const filters = {
        search: searchParams.get('search') ?? '',
        status: searchParams.get('status') ?? 'all',
        page: Number(searchParams.get('page') ?? 1),
    };

    function updateFilter(key: string, value: string) {
        setSearchParams((prev) => {
            if (value) prev.set(key, value);
            else prev.delete(key);
            if (key !== 'page') prev.set('page', '1');
            return prev;
        });
    }

    return (
        <>
            <input
                value={filters.search}
                onChange={(e) => updateFilter('search', e.target.value)}
            />
            <select
                value={filters.status}
                onChange={(e) => updateFilter('status', e.target.value)}
            >
                <option value="all">Все</option>
                <option value="published">Опубликованные</option>
                <option value="draft">Черновики</option>
            </select>
        </>
    );
}

useLocation

Альтернатива — читать location.search вручную:

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

const location = useLocation();
const params = new URLSearchParams(location.search);

Но useSearchParams удобнее.

Итоги

  • useSearchParams для query
  • get, getAll, set, delete
  • Фильтры и пагинация — в URL
  • Ссылка с параметрами — можно поделиться
  • useLocation как альтернатива