← Назад к вопросам
Какие аргументы принимает useEffect?
1.3 Junior🔥 101 комментариев
#Другое#Фреймворки и библиотеки
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI29 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
useEffect: Аргументы и правила использования
Это React хук для работы с побочными эффектами. Как backend разработчик, я часто взаимодействую с frontend через API и понимаю, как useEffect влияет на запросы к серверу.
Синтаксис
useEffect(() => {
// Побочный эффект
return () => {
// Очистка (cleanup функция)
};
}, [dependencies]);
Аргументы
1. Функция эффекта (обязателен)
useEffect(() => {
console.log('Компонент отрендерился или зависимости изменились');
// Здесь выполняются побочные эффекты:
// - API запросы
// - Подписка на события
// - Изменение DOM
// - Таймеры
});
2. Массив зависимостей (опционально)
Контролирует когда выполняется эффект:
// Без массива — выполняется после каждого рендера
useEffect(() => {
console.log('Выполнится после КАЖДОГО рендера');
});
// Пустой массив — выполняется один раз при монтировании
useEffect(() => {
console.log('Выполнится один раз при монтировании');
// Идеально для инициализации, загрузки начальных данных
}, []);
// С зависимостями — выполняется если они изменились
useEffect(() => {
fetch(`/api/users/${userId}`);
console.log('Выполнится если userId изменится');
}, [userId]);
Функция очистки (Cleanup)
Вторая функция внутри эффекта выполняется перед удалением компонента или перед следующим эффектом:
useEffect(() => {
// Подписка
const subscription = eventEmitter.subscribe('user-update', handleUpdate);
// Таймер
const timer = setTimeout(() => {
console.log('Отложенное действие');
}, 1000);
// Cleanup функция
return () => {
console.log('Очистка перед удалением или перед следующим эффектом');
subscription.unsubscribe();
clearTimeout(timer);
};
}, []);
Примеры использования
Загрузка данных с API
function UserProfile({ userId }) {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
let isMounted = true; // Защита от memory leak
const loadUser = async () => {
try {
setLoading(true);
const response = await fetch(`/api/users/${userId}`);
const data = await response.json();
if (isMounted) {
setUser(data);
setError(null);
}
} catch (err) {
if (isMounted) {
setError(err.message);
}
} finally {
if (isMounted) setLoading(false);
}
};
loadUser();
// Cleanup
return () => {
isMounted = false; // Предотвращение вызова setState после unmount
};
}, [userId]); // Перезагружаем если userId изменится
if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error}</div>;
return <div>User: {user.name}</div>;
}
WebSocket подписка
useEffect(() => {
const ws = new WebSocket('ws://localhost:3000/notifications');
ws.onmessage = (event) => {
const notification = JSON.parse(event.data);
console.log('Новое уведомление:', notification);
};
ws.onerror = (error) => {
console.error('WebSocket ошибка:', error);
};
// Cleanup
return () => {
ws.close();
};
}, []);
Частые ошибки
-
Бесконечный цикл — забыли массив зависимостей
// ❌ Плохо: выполняется при каждом рендере useEffect(() => { setData(newData); // Вызовет перерендер → новый эффект }); // ✅ Хорошо useEffect(() => { setData(newData); }, []); -
Memory leak — забыли очистку при unmount
// ❌ Плохо: setTimeout продолжит работать после удаления useEffect(() => { setTimeout(() => setData(newData), 1000); }, []); // ✅ Хорошо: очищаем таймер useEffect(() => { const timer = setTimeout(() => setData(newData), 1000); return () => clearTimeout(timer); }, []); -
Race conditions при асинхронных запросах
// ❌ Плохо: если userId меняется быстро, старый запрос перезапишет новые данные useEffect(() => { fetch(`/api/users/${userId}`).then(setUser); }, [userId]); // ✅ Хорошо: отменяем старые запросы useEffect(() => { let isMounted = true; fetch(`/api/users/${userId}`) .then(res => res.json()) .then(data => isMounted && setUser(data)); return () => { isMounted = false; }; }, [userId]);
Best Practices
- Используй AbortController для отмены запросов
- Группируй связанные эффекты в отдельные useEffect
- Не забывай про cleanup функции для подписок
- Перепроверяй массив зависимостей (используй плагин eslint-plugin-react-hooks)
- Для сложной логики — рассмотри useReducer
Понимание useEffect критично, так как он напрямую влияет на количество запросов к моему API и обработку асинхронных операций.