Комментарии (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>
);
}
Лучшие практики
- Используй async/await - читаемей чем .then()
- Обязательно обработай ошибки - try/catch или .catch()
- Очисти ресурсы - используй cleanup функцию с isMounted или AbortController
- Правильно указывай зависимости - избегай бесконечных циклов
- Создай переиспользуемый хук - useFetch для общей логики
- Не забывай про loading состояние - показывай пользователю, что идёт загрузка
- Валидируй URL - проверяй что URL не пуст перед запросом
Правильное управление API запросами в useEffect - это основа для надёжных React приложений.