Тема: Підключення до зовнішнього API. Використання JSONPlaceholder або власного бекенду для синхронізації даних додатку.
Мета: Опанувати роботу з мережевими запитами в екосистемі React; навчитися обробляти життєвий цикл асинхронних операцій (завантаження, успіх, помилка); використати хук useEffect для ініціалізації отримання даних від зовнішнього REST API (на прикладі JSONPlaceholder) та інтегрувати ці дані в існуючу архітектуру додатку (стрічку новин), створену в попередніх роботах.
Технологічний стек: React, Vite, Axios / Fetch API, Hooks (useEffect, useState).
Loading, Error, Data) для покращення користувацького досвіду (UX).useFetch для інкапсуляції логіки отримання даних.Для здійснення HTTP-запитів ми використовуватимемо бібліотеку axios (або вбудований fetch). Axios є галузевим стандартом, оскільки автоматично парсить JSON та краще обробляє помилки статусів.
Або встановіть axios у проекті:
npm install axios
Або продовжуйте використовувати нативний fetch. У цьому прикладі буде показано комбінований підхід (базовий fetch в кастомному хуку для універсальності).
Для уникнення дублювання логіки loading та error у кожному компоненті, створіть директорію src/hooks/ та файл useFetch.js (або .jsx).
import { useState, useEffect } from "react";
export const useFetch = (url) => {
const [data, setData] = useState(null);
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
// AbortController для скасування запиту,
// якщо компонент розмонтовується (захист від витоку пам'яті)
const abortController = new AbortController();
const fetchData = async () => {
setIsLoading(true);
try {
const response = await fetch(url, { signal: abortController.signal });
if (!response.ok) {
throw new Error(`Помилка HTTP: ${response.status}`);
}
const result = await response.json();
setData(result);
setError(null);
} catch (err) {
if (err.name === "AbortError") {
console.log("Запит скасовано");
} else {
setError(err.message);
}
} finally {
setIsLoading(false);
}
};
fetchData();
// Функція очищення (cleanup)
return () => {
abortController.abort();
};
}, [url]);
return { data, isLoading, error };
};
У Лабораторній роботі №2 ви створили компонент, який рендерить список. Тепер замінимо статичні дані на використання нашого хука. У цьому прикладі ми використовуємо публічне API JSONPlaceholder (повертає 100 публікацій).
NewsFeed.jsx:
import React from "react";
import { useFetch } from "../../hooks/useFetch";
// Імпортуйте ваш компонент картки з попередніх робіт
import PostCard from "../PostCard/PostCard";
const NewsFeed = () => {
// Викликаємо наш кастомний хук
const {
data: posts,
isLoading,
error,
} = useFetch("https://jsonplaceholder.typicode.com/posts");
// 1. Стан завантаження
if (isLoading) {
return <div className="spinner">Завантаження новин...</div>;
}
// 2. Стан помилки
if (error) {
return <div className="error-message">Сталася помилка: {error}</div>;
}
// 3. Стан успішного завантаження
return (
<div className="news-feed">
<h2>Останні публікації</h2>
<div className="posts-grid">
{posts &&
posts
.slice(0, 10)
.map((post) => (
<PostCard key={post.id} title={post.title} body={post.body} />
))}
</div>
</div>
);
};
export default NewsFeed;
Замініть синхронну імітацію входу у вашому AuthContext.jsx (або Login.jsx) на асинхронний запит. Оскільки JSONPlaceholder не має реальної системи авторизації, ми будемо імітувати запит з фіктивною затримкою, або звернемось до /users/1 для отримання профілю користувача.
Приклад асинхронного login у AuthContext.jsx:
const login = async (email) => {
try {
// Симуляція мережевої затримки для показу лоадера на кнопці
await new Promise((resolve) => setTimeout(resolve, 1000));
// "Стягуємо" дані фіктивного користувача
const response = await fetch(
"https://jsonplaceholder.typicode.com/users/1",
);
const userData = await response.json();
setIsAuthenticated(true);
// Зберігаємо справжні дані з АРІ у нашому стейті
setUser({ ...userData, email });
} catch (error) {
console.error("Помилка авторизації:", error);
}
};
Додайте локальний стейт isLoading у ваш компонент Login.jsx, щоб вимикати кнопку (робити disabled) під час відправки запиту на сервер.
AbortController у нашому хуку useFetch. Яку загрозу для React-додатку він усуває?loading, error, data) при роботі з мережею і чому він є обов’язковим для якісного UX?fetch або axios.get) розміщується всередині хука useEffect, а не прямо в тілі функціонального компонента?axios у порівнянні з нативним fetch (якщо студенти використовували її під час самостійної розробки)?lab_06.md винести фрагменти коду:
useFetch.jsx.isLoading та списку елементів).lab_06.md дати вичерпні й аргументовані відповіді на 5 контрольних запитань.