React useEffect: загрузить данные асинхронно

Категория: JavaScript · Язык: JavaScript · Обновлено:

Чтобы загрузить данные в useEffect, объявите асинхронную функцию внутри эффекта и вызовите её: сам callback эффекта не должен быть async, потому что React ожидает функцию очистки или undefined. Передавайте AbortSignal, чтобы отменить запрос при смене параметров или размонтировании.

Запрос с AbortController

JavaScript
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 запустит очистку предыдущего эффекта перед следующим запуском.

Неправильно

Почему

useEffect(async () => {...})

Callback возвращает Promise вместо cleanup-функции

Игнорировать response.ok

HTTP 404/500 не вызывает автоматический reject у fetch

Не отменять старый запрос

Устаревший ответ может перезаписать новое состояние

Почему эффект выполняется дважды?

В режиме разработки Strict Mode может смонтировать, очистить и повторно запустить эффект. Это помогает найти ошибки cleanup и не означает, что production-поведение будет таким же.

Надо ли добавлять функцию загрузки в зависимости?

Функцию, объявленную внутри эффекта, добавлять не нужно. Включите все внешние значения, которые эффект читает, в массив зависимостей.