Пошук уроків, статей та іншого контенту
Отримаєте параметри шляху за допомогою useParams і використаєте їх для завантаження потрібних даних.
Параметр шляху — це динамічна частина URL, яка позначається двокрапкою в описі маршруту.
Наприклад, у маршруті:
<Route path="/posts/:postId" element={<PostDetails />} />частина
:postId/posts/1
/posts/25
/posts/abcзначення параметра postId буде відповідно:
"1"
"25"
"abc"Параметри шляху зручно використовувати, коли потрібно показати сторінку конкретного ресурсу:
користувача за ідентифікатором;
товар за артикулом;
статтю за slug;
коментар за ідентифікатором.
useParamsReact Router надає хук useParams, який повертає об’єкт із параметрами поточного маршруту.
import { useParams } from "react-router-dom";
function PostDetails() {
const { postId } = useParams();
return <h1>Ідентифікатор публікації: {postId}</h1>;
}Якщо користувач відкриє адресу /posts/42, компонент отримає:
{
postId: "42"
}Зверніть увагу: значення параметра завжди є рядком. Навіть якщо URL містить число 42, useParams поверне "42".
За потреби рядок можна перетворити на число:
const { postId } = useParams();
const numericPostId = Number(postId);Назва параметра має збігатися в описі маршруту та під час деструктуризації.
<Route path="/users/:userId" element={<UserDetails />} />function UserDetails() {
const { userId } = useParams();
return <p>Користувач: {userId}</p>;
}Якщо в маршруті використати :userId, а в компоненті спробувати отримати postId, значення postId буде undefined.
Типовий сценарій:
Отримати параметр через useParams.
Виконати запит до API з використанням цього параметра.
Зберегти отримані дані у стані.
Показати стан завантаження або помилку.
Повторити запит, якщо параметр змінився.
Для цього зазвичай використовують useEffect. Параметр потрібно додати до масиву залежностей, щоб при переході між різними ресурсами дані оновлювалися.
У цьому прикладі маршрут /posts/:postId показує деталі публікації. Ідентифікатор із URL використовується для запиту до API.
import { useEffect, useState } from "react";
import {
BrowserRouter,
Link,
Route,
Routes,
useParams,
} from "react-router-dom";
function HomePage() {
return (
<main>
<h1>Публікації</h1>
<ul>
<li>
<Link to="/posts/1">Публікація 1</Link>
</li>
<li>
<Link to="/posts/2">Публікація 2</Link>
</li>
<li>
<Link to="/posts/3">Публікація 3</Link>
</li>
</ul>
</main>
);
}
function PostDetails() {
const { postId } = useParams();
const [post, setPost] = useState(null);
const [status, setStatus] = useState("loading");
const [error, setError] = useState("");
useEffect(() => {
const controller = new AbortController();
async function loadPost() {
setStatus("loading");
setError("");
setPost(null);
try {
const response = await fetch(
`https://jsonplaceholder.typicode.com/posts/${postId}`,
{
signal: controller.signal,
},
);
if (!response.ok) {
throw new Error("Не вдалося завантажити публікацію");
}
const data = await response.json();
if (!data.id) {
throw new Error("Публікацію не знайдено");
}
setPost(data);
setStatus("success");
} catch (requestError) {
if (requestError.name === "AbortError") {
return;
}
setError(requestError.message);
setStatus("error");
}
}
loadPost();
return () => {
controller.abort();
};
}, [postId]);
if (status === "loading") {
return <p>Завантаження публікації...</p>;
}
if (status === "error") {
return <p role="alert">{error}</p>;
}
return (
<main>
<Link to="/">← До списку публікацій</Link>
<article>
<h1>{post.title}</h1>
<p>{post.body}</p>
</article>
</main>
);
}
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<HomePage />} />
<Route path="/posts/:postId" element={<PostDetails />} />
<Route path="*" element={<p>Сторінку не знайдено</p>} />
</Routes>
</BrowserRouter>
);
}
export default App;У цьому прикладі:
:postId оголошено в маршруті;
useParams() отримує значення postId;
значення параметра додається до URL запиту;
залежність [postId] запускає ефект повторно при зміні публікації;
AbortController скасовує попередній запит, якщо користувач швидко переходить на іншу публікацію.
Розглянемо послідовність переходів:
/posts/1
/posts/2Компонент маршруту може залишитися тим самим, але значення postId зміниться:
"1" → "2"Саме тому недостатньо виконати запит лише під час першого монтування компонента. postId має бути залежністю useEffect:
useEffect(() => {
loadPost(postId);
}, [postId]);Якщо залишити масив залежностей порожнім:
useEffect(() => {
loadPost(postId);
}, []);запит виконається тільки один раз. Після переходу на інший параметр компонент може не завантажити нові дані.
Маршрут може містити кілька параметрів:
<Route
path="/users/:userId/posts/:postId"
element={<UserPost />}
/>Для URL:
/users/7/posts/42компонент отримає обидва значення:
import { useParams } from "react-router-dom";
function UserPost() {
const { userId, postId } = useParams();
return (
<p>
Користувач {userId}, публікація {postId}
</p>
);
}Результат:
Користувач 7, публікація 42Якщо запит залежить від кількох параметрів, усі вони мають бути в масиві залежностей ефекту:
const { userId, postId } = useParams();
useEffect(() => {
// Завантаження даних користувача та публікації
}, [userId, postId]);Оскільки параметри URL є рядками, їх потрібно перевіряти перед використанням. Наприклад, якщо API очікує числовий ідентифікатор:
const { postId } = useParams();
const numericPostId = Number(postId);
if (!Number.isInteger(numericPostId) || numericPostId <= 0) {
return <p>Некоректний ідентифікатор публікації</p>;
}Перевірка особливо важлива, якщо параметр використовується:
у математичних операціях;
як числовий ідентифікатор у запиті;
для доступу до масиву за індексом;
у логіці порівняння.
Компонент не отримає значення, якщо параметр не оголошений у path.
Неправильно:
<Route path="/posts" element={<PostDetails />} />function PostDetails() {
const { postId } = useParams();
// postId буде undefined
}Правильно:
<Route path="/posts/:postId" element={<PostDetails />} />Неправильно:
<Route path="/posts/:postId" element={<PostDetails />} />
function PostDetails() {
const { id } = useParams();
// id буде undefined
}Правильно:
function PostDetails() {
const { postId } = useParams();
return <p>{postId}</p>;
}useEffectНеправильно:
useEffect(() => {
loadPost(postId);
}, []);У такому випадку дані не оновляться після переходу з /posts/1 на /posts/2.
Правильно:
useEffect(() => {
loadPost(postId);
}, [postId]);Неправильно:
const { postId } = useParams();
if (postId > 10) {
// Значення все одно отримане як рядок
}Краще явно перетворити та перевірити значення:
const numericPostId = Number(postId);
if (numericPostId > 10) {
// Робота з числом
}useParams поза маршрутомuseParams отримує параметри з поточного збігу маршруту. Компонент має бути відрендерений через маршрут, який містить відповідний параметр:
<Routes>
<Route path="/posts/:postId" element={<PostDetails />} />
</Routes>Якщо відрендерити PostDetails у місці, де немає такого маршруту, потрібний параметр буде відсутній.
Динамічна частина маршруту позначається двокрапкою: :postId.
Хук useParams повертає параметри поточного URL.
Значення параметрів завжди є рядками.
Параметр можна використовувати для формування URL запиту до API.
Параметри, від яких залежить завантаження, потрібно додавати до масиву залежностей useEffect.
Перед використанням числові параметри потрібно перетворювати та перевіряти.
Один маршрут може містити кілька параметрів.