Пошук уроків, статей та іншого контенту
Ознайомитеся з Fetch API та навчитеся виконувати HTTP-запити з React-компонентів.
Fetch API — це вбудований браузерний API для виконання HTTP-запитів. За допомогою fetch() React-компонент може отримувати дані із сервера або надсилати на сервер нові дані.
Найпростіший GET-запит:
fetch("https://jsonplaceholder.typicode.com/users")
.then((response) => response.json())
.then((users) => {
console.log(users);
})
.catch((error) => {
console.error("Помилка запиту:", error);
});Метод fetch() повертає проміс:
Перший .then() отримує об’єкт відповіді сервера.
response.json() перетворює JSON-відповідь на JavaScript-дані.
Наступний .then() отримує готові дані.
.catch() обробляє помилки мережі.
У сучасному коді зазвичай використовують async/await, оскільки такий синтаксис легше читати:
async function loadUsers() {
try {
const response = await fetch(
"https://jsonplaceholder.typicode.com/users"
);
const users = await response.json();
console.log(users);
} catch (error) {
console.error("Помилка запиту:", error);
}
}
loadUsers();React-компонент може виконати запит після свого монтування. Для цього використовують хук useEffect.
useState зберігає отримані дані, стан завантаження та помилку.
useEffect запускає запит у потрібний момент.
import { useEffect, useState } from "react";
function UsersList() {
const [users, setUsers] = useState([]);
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState("");
useEffect(() => {
async function loadUsers() {
try {
const response = await fetch(
"https://jsonplaceholder.typicode.com/users"
);
if (!response.ok) {
throw new Error("Не вдалося отримати список користувачів");
}
const data = await response.json();
setUsers(data);
} catch (requestError) {
setError(requestError.message);
} finally {
setIsLoading(false);
}
}
loadUsers();
}, []);
if (isLoading) {
return <p>Завантаження...</p>;
}
if (error) {
return <p>Помилка: {error}</p>;
}
return (
<ul>
{users.map((user) => (
<li key={user.id}>
{user.name} — {user.email}
</li>
))}
</ul>
);
}
export default UsersList;const [users, setUsers] = useState([]);users містить список користувачів, а setUsers оновлює цей список.
const [isLoading, setIsLoading] = useState(true);Поки запит виконується, isLoading дорівнює true. Після завершення запиту ми змінюємо його значення на false.
useEffect(() => {
// запит
}, []);Порожній масив залежностей означає, що ефект запускається після першого відображення компонента.
const response = await fetch("...");Виконується HTTP-запит.
if (!response.ok) {
throw new Error("...");
}Властивість ok дорівнює true, якщо HTTP-статус відповіді знаходиться в діапазоні від 200 до 299.
Важливо: fetch() не вважає статуси 404 або 500 мережевою помилкою автоматично. Тому статус потрібно перевіряти самостійно через response.ok.
const data = await response.json();Тіло відповіді перетворюється з JSON на масив або об’єкт JavaScript.
setUsers(data);Після оновлення стану React повторно відобразить компонент і покаже отримані дані.
Нижче наведено готовий компонент, який можна використовувати у React-проєкті:
import { useEffect, useState } from "react";
function App() {
const [users, setUsers] = useState([]);
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState("");
useEffect(() => {
const controller = new AbortController();
async function fetchUsers() {
try {
const response = await fetch(
"https://jsonplaceholder.typicode.com/users",
{
signal: controller.signal,
}
);
if (!response.ok) {
throw new Error(`Помилка сервера: ${response.status}`);
}
const data = await response.json();
setUsers(data);
} catch (requestError) {
// Скасований запит не потрібно показувати як помилку
if (requestError.name !== "AbortError") {
setError(requestError.message);
}
} finally {
// Після скасування компонент може бути вже неактивним
if (!controller.signal.aborted) {
setIsLoading(false);
}
}
}
fetchUsers();
return () => {
// Скасовуємо запит, якщо компонент буде видалено
controller.abort();
};
}, []);
return (
<main>
<h1>Користувачі</h1>
{isLoading && <p>Завантаження...</p>}
{error && <p>Помилка: {error}</p>}
{!isLoading && !error && (
<ul>
{users.map((user) => (
<li key={user.id}>
<strong>{user.name}</strong>
<br />
<span>{user.email}</span>
</li>
))}
</ul>
)}
</main>
);
}
export default App;Компонент може бути видалений зі сторінки раніше, ніж завершиться запит. Наприклад, користувач перейшов на іншу сторінку.
Для скасування запиту використовують AbortController:
const controller = new AbortController();
fetch(url, {
signal: controller.signal,
});
controller.abort();У React скасування запиту виконується у функції очищення, яку повертає useEffect:
useEffect(() => {
const controller = new AbortController();
// Виконання запиту з controller.signal
return () => {
controller.abort();
};
}, []);Це допомагає не виконувати зайві операції після того, як компонент перестав існувати.
Параметри можна додати безпосередньо до URL:
const userId = 3;
const response = await fetch(
`https://jsonplaceholder.typicode.com/posts?userId=${userId}`
);У цьому прикладі серверу надсилається запит:
/posts?userId=3Повний приклад завантаження дописів конкретного користувача:
import { useEffect, useState } from "react";
function UserPosts({ userId }) {
const [posts, setPosts] = useState([]);
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
async function loadPosts() {
setIsLoading(true);
try {
const response = await fetch(
`https://jsonplaceholder.typicode.com/posts?userId=${userId}`
);
if (!response.ok) {
throw new Error("Не вдалося завантажити дописи");
}
const data = await response.json();
setPosts(data);
} catch (error) {
console.error(error);
} finally {
setIsLoading(false);
}
}
loadPosts();
}, [userId]);
if (isLoading) {
return <p>Завантаження дописів...</p>;
}
return (
<ul>
{posts.map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
);
}
export default UserPosts;Залежність [userId] означає, що ефект буде повторно виконано, коли значення userId зміниться.
Fetch API підтримує різні HTTP-методи. Для надсилання даних зазвичай використовують POST.
async function createPost() {
const response = await fetch(
"https://jsonplaceholder.typicode.com/posts",
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
title: "Новий допис",
body: "Текст нового допису",
userId: 1,
}),
}
);
if (!response.ok) {
throw new Error("Не вдалося створити допис");
}
const createdPost = await response.json();
console.log(createdPost);
}
createPost().catch((error) => {
console.error("Помилка:", error);
});Основні параметри POST-запиту:
method визначає HTTP-метод;
headers описує формат даних;
body містить дані запиту;
JSON.stringify() перетворює JavaScript-об’єкт на JSON-рядок.
У React POST-запит часто запускають після події, наприклад натискання кнопки або надсилання форми.
Для інтерфейсу зазвичай потрібно зберігати три стани:
Завантаження — запит ще виконується.
Успіх — дані отримано.
Помилка — запит не вдався.
Приклад умовного відображення:
if (isLoading) {
return <p>Завантаження...</p>;
}
if (error) {
return <p>Сталася помилка: {error}</p>;
}
return <p>Дані успішно завантажено</p>;Такий підхід не залишає користувача без пояснення, що відбувається під час виконання запиту.
useEffectНе варто викликати fetch() безпосередньо в тілі компонента:
function UsersList() {
fetch("/api/users");
return <p>Користувачі</p>;
}Компонент може відображатися багато разів. У результаті запит виконуватиметься знову після кожного повторного відображення.
Для запитів після відображення компонента використовуйте useEffect.
useEffect(() => {
loadUsers();
});Без другого аргументу ефект запускається після кожного відображення компонента. Якщо всередині ефекту оновлюється стан, це може спричинити нескінченні повторні запити.
Якщо запит потрібно виконати один раз:
useEffect(() => {
loadUsers();
}, []);response.okconst response = await fetch(url);
const data = await response.json();Такий код може спробувати обробити відповідь із помилкою сервера як звичайні дані.
Краще перевіряти статус:
if (!response.ok) {
throw new Error("Помилка HTTP-запиту");
}await response.json()fetch() повертає об’єкт Response, а не готові дані:
const response = await fetch(url);Щоб отримати JSON:
const data = await response.json();key під час відображення спискуПід час використання map() кожен елемент списку повинен мати стабільний key:
{users.map((user) => (
<li key={user.id}>{user.name}</li>
))}Зазвичай як key використовують унікальний ідентифікатор, отриманий від сервера.
fetch() виконує HTTP-запити з браузера.
Для запитів у React-компонентах зазвичай використовують useEffect.
Отримані дані зберігають у стані через useState.
Відповідь JSON потрібно перетворити за допомогою response.json().
Статус відповіді потрібно перевіряти через response.ok.
Інтерфейс має обробляти стани завантаження, успіху та помилки.
Масив залежностей useEffect визначає, коли повторно виконувати запит.
AbortController дає змогу скасувати запит, коли компонент видаляється.