Урок 03

Динамические маршруты

Динамические маршруты содержат параметр, который меняется. Например, /posts/5, /users/alice, /products/123.

Объявление

<Route path="/posts/:id" element={<PostDetail />} />

Двоеточие — параметр. Имя (id) любое.

useParams

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

function PostDetail() {
    const { id } = useParams<{ id: string }>();

    return <p>Пост {id}</p>;
}

useParams возвращает объект с параметрами маршрута.

Несколько параметров

<Route path="/users/:userId/posts/:postId" element={<UserPost />} />

function UserPost() {
    const { userId, postId } = useParams();
    return <p>Пользователь {userId}, пост {postId}</p>;
}

Использование ID для запроса

function PostDetail() {
    const { id } = useParams<{ id: string }>();
    const [post, setPost] = useState<Post | null>(null);

    useEffect(() => {
        fetch(`/api/posts/${id}`)
            .then((r) => r.json())
            .then(setPost);
    }, [id]);

    if (!post) return <p>Загрузка...</p>;

    return <h1>{post.title}</h1>;
}

Следи за id в зависимостях — при смене параметра запрос повторяется.

Использование slug

<Route path="/posts/:slug" element={<PostDetail />} />

Slug — человекочитаемый идентификатор: hello-world вместо 5. Удобно для SEO и ссылок.

Опциональный параметр

В React Router v6/v7 нет опционального :id? в пути, но можно объявить два маршрута:

<Route path="/posts" element={<Posts />} />
<Route path="/posts/:id" element={<PostDetail />} />

Или использовать ? для query:

/posts?page=2&sort=date
const [searchParams] = useSearchParams();
const page = searchParams.get('page');

Вложенные динамические маршруты

<Route path="/posts/:postId" element={<PostLayout />}>
    <Route index element={<PostView />} />
    <Route path="comments" element={<PostComments />} />
    <Route path="edit" element={<PostEdit />} />
</Route>

Родитель получает postId, дети — тоже через useParams.

Проверка параметра

function PostDetail() {
    const { id } = useParams();

    if (!id || isNaN(Number(id))) {
        return <NotFound />;
    }

    // ...
}

Типизация

type Params = {
    id: string;
    tab?: string;
};

const { id } = useParams<Params>();

В React Router v7 типы можно выводить из определений маршрутов.

Итоги

  • :param в path для динамических частей
  • useParams для чтения
  • Несколько параметров — по имени
  • Следи за зависимостями в useEffect
  • Slug — для SEO-ссылок
  • Опциональность — через два маршрута