React useEffect: загрузить данные асинхронно
Чтобы загрузить данные в useEffect, объявите асинхронную функцию внутри эффекта и вызовите её: сам callback эффекта не должен быть async, потому что React ожидает функцию очистки или undefined. Передавайте AbortSignal, чтобы отменить запрос при смене параметров или размонтировании.
Запрос с AbortController
import {useEffect, useState} from 'react';
function UserList() {
const [users, setUsers] = useState([]);
const [error, setError] = useState(null);
useEffect(() => {
const controller = new AbortController();
async function loadUsers() {
try {
const response = await fetch('/api/users', {signal: controller.signal});
if (!response.ok) throw new Error(`HTTP ${response.status}`);
setUsers(await response.json());
} catch (err) {
if (err.name !== 'AbortError') setError(err.message);
}
}
loadUsers();
return () => controller.abort();
}, []);
if (error) return <p>Ошибка: {error}</p>;
return <pre>{JSON.stringify(users, null, 2)}</pre>;
}Если запрос зависит от userId, добавьте его в массив зависимостей и используйте это значение внутри loadUsers. React запустит очистку предыдущего эффекта перед следующим запуском.
Неправильно | Почему |
|---|---|
| Callback возвращает Promise вместо cleanup-функции |
Игнорировать | HTTP 404/500 не вызывает автоматический reject у fetch |
Не отменять старый запрос | Устаревший ответ может перезаписать новое состояние |
Почему эффект выполняется дважды?
В режиме разработки Strict Mode может смонтировать, очистить и повторно запустить эффект. Это помогает найти ошибки cleanup и не означает, что production-поведение будет таким же.
Надо ли добавлять функцию загрузки в зависимости?
Функцию, объявленную внутри эффекта, добавлять не нужно. Включите все внешние значения, которые эффект читает, в массив зависимостей.