← Назад к вопросам

Как отправить запрос в UseEffect?

2.0 Middle🔥 291 комментариев
#React

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI3 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Отправка API запросов в useEffect

В React useEffect - это хук для выполнения побочных эффектов, включая загрузку данных. Вот правильные способы сделать это.

1. Базовый пример с fetch

Просто выполни запрос в useEffect:

function UserProfile() {
  const [user, setUser] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    // Выполнить запрос при монтировании компонента
    fetch('/api/user')
      .then((response) => response.json())
      .then((data) => {
        setUser(data);
        setLoading(false);
      })
      .catch((error) => {
        console.error('Ошибка:', error);
        setLoading(false);
      });
  }, []); // Пустой массив зависимостей = только при монтировании

  if (loading) return <div>Загрузка...</div>;
  return <div>Пользователь: {user.name}</div>;
}

2. С async/await (рекомендуемый способ)

Лучше использовать async/await для читаемости:

function UserProfile() {
  const [user, setUser] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    // Создаю вложенную async функцию
    const fetchUser = async () => {
      try {
        const response = await fetch('/api/user');
        
        if (!response.ok) {
          throw new Error(`HTTP Error: ${response.status}`);
        }
        
        const data = await response.json();
        setUser(data);
      } catch (err) {
        setError(err.message);
      } finally {
        setLoading(false);
      }
    };

    fetchUser();
  }, []); // Зависимости: пусто = один раз при монтировании

  if (loading) return <div>Загрузка...</div>;
  if (error) return <div>Ошибка: {error}</div>;
  return <div>Пользователь: {user?.name}</div>;
}

3. С зависимостями (пересчёт при изменении)

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

function UserProfile({ userId }) {
  const [user, setUser] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    setLoading(true);
    
    const fetchUser = async () => {
      try {
        const response = await fetch(`/api/users/${userId}`);
        const data = await response.json();
        setUser(data);
      } finally {
        setLoading(false);
      }
    };

    if (userId) {
      fetchUser();
    }
  }, [userId]); // Повторить запрос когда userId изменится

  if (loading) return <div>Загрузка...</div>;
  return <div>Пользователь: {user?.name}</div>;
}

4. Очистка (cleanup function)

Очистка необходима, чтобы избежать утечек памяти:

function SearchUsers() {
  const [users, setUsers] = useState([]);
  const [query, setQuery] = useState('');

  useEffect(() => {
    let isMounted = true; // Флаг для отслеживания монтирования

    const searchUsers = async () => {
      try {
        const response = await fetch(`/api/users?q=${query}`);
        const data = await response.json();
        
        // Только обновляем, если компонент ещё монтирован
        if (isMounted) {
          setUsers(data);
        }
      } catch (error) {
        console.error('Ошибка поиска:', error);
      }
    };

    if (query.length > 0) {
      searchUsers();
    }

    // Cleanup функция
    return () => {
      isMounted = false; // Компонент демонтировался
    };
  }, [query]); // Повторить поиск при изменении query

  return (
    <div>
      <input 
        value={query} 
        onChange={(e) => setQuery(e.target.value)} 
        placeholder="Поиск..."
      />
      <ul>
        {users.map((user) => (
          <li key={user.id}>{user.name}</li>
        ))}
      </ul>
    </div>
  );
}

5. Использование AbortController для отмены

Модернизированный способ отмены запроса:

function UserList() {
  const [users, setUsers] = useState([]);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    const controller = new AbortController(); // Создаю контроллер

    const fetchUsers = async () => {
      try {
        const response = await fetch('/api/users', {
          signal: controller.signal // Передаю сигнал
        });
        const data = await response.json();
        setUsers(data);
      } catch (error) {
        if (error.name !== 'AbortError') {
          console.error('Ошибка:', error);
        }
      } finally {
        setLoading(false);
      }
    };

    fetchUsers();

    // Cleanup - отмени запрос если компонент демонтировался
    return () => {
      controller.abort();
    };
  }, []);

  if (loading) return <div>Загрузка...</div>;
  return (
    <ul>
      {users.map((user) => (
        <li key={user.id}>{user.name}</li>
      ))}
    </ul>
  );
}

6. Работа с axios

Если используешь axios вместо fetch:

import axios from 'axios';

function PostList() {
  const [posts, setPosts] = useState([]);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    const fetchPosts = async () => {
      try {
        const response = await axios.get('/api/posts');
        setPosts(response.data);
      } catch (error) {
        console.error('Ошибка:', error.message);
      } finally {
        setLoading(false);
      }
    };

    fetchPosts();
  }, []);

  if (loading) return <div>Загрузка...</div>;
  return (
    <ul>
      {posts.map((post) => (
        <li key={post.id}>{post.title}</li>
      ))}
    </ul>
  );
}

7. Общий хук для API запросов

Лучше всего создать переиспользуемый хук:

function useFetch(url, options = {}) {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    const controller = new AbortController();

    const fetchData = async () => {
      try {
        const response = await fetch(url, {
          ...options,
          signal: controller.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') {
          setError(err.message);
          setData(null);
        }
      } finally {
        setLoading(false);
      }
    };

    fetchData();

    return () => controller.abort();
  }, [url, options]);

  return { data, loading, error };
}

// Использование:
function App() {
  const { data: users, loading, error } = useFetch('/api/users');

  if (loading) return <div>Загрузка...</div>;
  if (error) return <div>Ошибка: {error}</div>;

  return <div>{users.map(u => <div key={u.id}>{u.name}</div>)}</div>;
}

8. Последовательные запросы

Когда один запрос зависит от результата другого:

function UserWithPosts({ userId }) {
  const [user, setUser] = useState(null);
  const [posts, setPosts] = useState([]);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    const fetchData = async () => {
      try {
        // Первый запрос
        const userRes = await fetch(`/api/users/${userId}`);
        const userData = await userRes.json();
        setUser(userData);

        // Второй запрос зависит от первого
        const postsRes = await fetch(`/api/users/${userId}/posts`);
        const postsData = await postsRes.json();
        setPosts(postsData);
      } catch (error) {
        console.error('Ошибка:', error);
      } finally {
        setLoading(false);
      }
    };

    fetchData();
  }, [userId]);

  if (loading) return <div>Загрузка...</div>;
  return (
    <div>
      <h1>{user?.name}</h1>
      <ul>
        {posts.map((post) => (
          <li key={post.id}>{post.title}</li>
        ))}
      </ul>
    </div>
  );
}

Лучшие практики

  1. Используй async/await - читаемей чем .then()
  2. Обязательно обработай ошибки - try/catch или .catch()
  3. Очисти ресурсы - используй cleanup функцию с isMounted или AbortController
  4. Правильно указывай зависимости - избегай бесконечных циклов
  5. Создай переиспользуемый хук - useFetch для общей логики
  6. Не забывай про loading состояние - показывай пользователю, что идёт загрузка
  7. Валидируй URL - проверяй что URL не пуст перед запросом

Правильное управление API запросами в useEffect - это основа для надёжных React приложений.

Как отправить запрос в UseEffect? | PrepBro