Коротка відповідь
junioruseEffect — це найкращий місце для серверних запитів, бо він виконується після рендеру і не блокує UI. useEffect дозволяє контролювати залежності, що запобігає зайвим викликам. При очищенні useEffect можна відмінити запит, щоб уникнути memory leaks.
Повне пояснення
Що це і навіщо
Запити на сервер зазвичай виконуються в useEffect (React hooks) або у методі componentDidMount класових компонентів. Це забезпечує, що запит відбудеться після того, як DOM вже створений.
Ключові принципи
- useEffect виконується після рендеру, тому UI не блокується.
- Залежності (
[]) визначають коли повторювати запит. - Повернення функції очищення (
return () => ...) дозволяє відмінити запит при демонтажі.
Як це працює
- Компонент рендериться.
- React викликає
useEffectпісля оновлення DOM. - В середині
useEffectзапускається асинхронний запит. - Після отримання відповіді оновлюється стан, що викликає повторний рендер.
- Якщо компонент демонтується до завершення запиту, функція очищення скасовує його.
Практика і реалізація (JS/TS)
import { useEffect, useState } from 'react';
function UserList() {
const [users, setUsers] = useState([]);
useEffect(() => {
const controller = new AbortController();
fetch('/api/users', { signal: controller.signal })
.then(r => r.json())
.then(setUsers)
.catch(err => {
if (err.name !== 'AbortError') console.error(err);
});
return () => controller.abort(); // очищення
}, []); // один раз після mount
return <ul>{users.map(u => <li key={u.id}>{u.name}</li>)}</ul>;
}
Тестування
- Unit: мокати
fetchі перевіряти, щоsetUsersвикликано. - Integration: використовувати
@testing-library/reactзjest-fetch-mock.
Безпека і приватність
- Використовувати
AbortControllerдля скасування небажаних запитів. - Перевіряти статус відповіді і обробляти помилки.
Оптимізація
- Кешувати відповіді (наприклад, через
React Query). - Використовувати
useMemo/useCallback, щоб уникнути зайвих рендерів.
Часті помилки
- Запит у конструкторі класу → блокує UI.
- Не очищати
useEffect→ memory leaks. - Відсутність залежностей → нескінченний цикл запитів.
- Не обробляти
AbortError→ зайві логи. - Використання
setStateпісля демонтажу → warning. - Не перевіряти статус HTTP → неочікувані дані.
- Занадто часті запити без debounce → навантаження на сервер.
- Не використовувати
async/awaitуuseEffect→ складність обробки.
Cheatsheet
- Запит:
useEffect(() => { /* fetch */ }, []) - Скасування:
return () => controller.abort(); - Проблема: “setState on unmounted component” → використати
AbortController. - Питання: “Чому не в конструкторі?” – відповідає, що це блокує UI і викликає помилки.