← Назад к вопросам
Как будет работать useEffect, если массива зависимостей нет?
1.6 Junior🔥 131 комментариев
#React
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Как будет работать useEffect, если массива зависимостей нет
Если у useEffect нет массива зависимостей, эффект будет запускаться ПОСЛЕ КАЖДОГО рендера компонента. Это критически важная особенность, которая часто приводит к багам и бесконечным циклам.
Три варианта useEffect
// 1. БЕЗ массива зависимостей — запускается после каждого рендера
useEffect(() => {
console.log('Запускается после КАЖДОГО рендера');
});
// 2. С ПУСТЫМ массивом — запускается только ОДИН РАЗ при монтировании
useEffect(() => {
console.log('Запускается только при монтировании');
}, []);
// 3. С ЗАВИСИМОСТЯМИ — запускается, когда зависимости меняются
useEffect(() => {
console.log('Запускается когда value меняется');
}, [value]);
Пример: useEffect БЕЗ массива зависимостей
function UserProfile({ userId }) {
const [user, setUser] = useState(null);
// БЕЗ массива зависимостей
useEffect(() => {
console.log('Запрос данных пользователя');
fetch(`/api/users/${userId}`)
.then(res => res.json())
.then(data => setUser(data));
}); // <- НЕТУ массива зависимостей!
return <div>{user?.name}</div>;
}
Что произойдёт:
1. Компонент монтируется
2. useEffect запускается -> fetch запрос
3. Получаем данные -> setUser(data)
4. Компонент ре-рендерится
5. useEffect запускается СНОВА -> ещё один fetch запрос
6. Получаем данные -> setUser(data)
7. Компонент ре-рендерится
8. Шаг 5-7 повторяются БЕСКОНЕЧНО!
Результат: бесконечный цикл запросов!
Визуализация жизненного цикла
function Counter() {
const [count, setCount] = useState(0);
// БЕЗ массива зависимостей
useEffect(() => {
console.log('Effect запустился. Count = ' + count);
});
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>+1</button>
</div>
);
}
Вывод в консоли:
Effect запустился. Count = 0 (первый рендер)
Effect запустился. Count = 1 (клик на кнопку)
Effect запустился. Count = 2 (клик на кнопку)
Effect запустился. Count = 3 (клик на кнопку)
...
После каждого клика на кнопку effect запускается!
Правильные варианты
1. С пустым массивом зависимостей (mount/unmount)
function UserProfile({ userId }) {
const [user, setUser] = useState(null);
// С ПУСТЫМ массивом — запускается ОД ОДИН РАЗ
useEffect(() => {
console.log('Component mounted');
fetch(`/api/users/${userId}`)
.then(res => res.json())
.then(data => setUser(data));
return () => {
console.log('Component unmounted');
};
}, []); // <- пустой массив!
return <div>{user?.name}</div>;
}
// Вывод:
// Component mounted (один раз)
// fetch запрос сделается один раз
2. С зависимостями (когда зависимость меняется)
function UserProfile({ userId }) {
const [user, setUser] = useState(null);
// С ЗАВИСИМОСТЯМИ — запускается, когда userId меняется
useEffect(() => {
console.log(`Загружаю пользователя ${userId}`);
fetch(`/api/users/${userId}`)
.then(res => res.json())
.then(data => setUser(data));
}, [userId]); // <- userId это зависимость!
return <div>{user?.name}</div>;
}
// Вывод:
// Загружаю пользователя 1 (userId=1 впервые)
// Загружаю пользователя 2 (userId изменился на 2)
// Загружаю пользователя 3 (userId изменился на 3)
Когда useEffect БЕЗ зависимостей может быть полезен
Очень редко! Но есть случаи:
1. Отслеживание всех рендеров для отладки
function DebugComponent() {
const [count, setCount] = useState(0);
useEffect(() => {
console.log('Component rendered. Time:', new Date().toLocaleTimeString());
}); // Без зависимостей — логируем каждый рендер
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Render me</button>
</div>
);
}
2. Отправка аналитики
function AnalyticsComponent() {
useEffect(() => {
// Отправляем событие при каждом рендере
analytics.trackPageView({
timestamp: Date.now(),
pathname: window.location.pathname
});
}); // Без зависимостей — отправляем при каждом рендере
}
НО: в 99% случаев это ошибка!
Типичная ошибка с бесконечным циклом
// ПЛОХО: бесконечный цикл
function BadComponent() {
const [data, setData] = useState([]);
useEffect(() => {
fetch('/api/data')
.then(res => res.json())
.then(newData => setData(newData)); // Вызывает рендер
}); // <- БЕЗ зависимостей!
// Результат:
// 1. Рендер -> useEffect
// 2. setData -> рендер
// 3. useEffect запускается СНОВА
// 4. setData -> рендер
// ... БЕСКОНЕЧНО
}
// ХОРОШО: зависимости
function GoodComponent() {
const [data, setData] = useState([]);
useEffect(() => {
fetch('/api/data')
.then(res => res.json())
.then(newData => setData(newData));
}, []); // <- пустой массив, запуск один раз
}
Чистка сайд-эффектов
function SubscriptionComponent({ userId }) {
const [messages, setMessages] = useState([]);
useEffect(() => {
// Подписываемся на сообщения
const unsubscribe = subscribeToMessages(userId, (msg) => {
setMessages(prev => [...prev, msg]);
});
// Cleanup функция
return () => {
console.log('Cleaning up subscription');
unsubscribe(); // Отписываемся
};
}, [userId]); // Переподписываемся, когда userId меняется
return <div>{messages.length} messages</div>;
}
// Вывод:
// userId=1: Подписались
// userId=2: Cleaning up subscription + Подписались снова
// userId=3: Cleaning up subscription + Подписались снова
React Strict Mode и двойной эффект
function StrictModeComponent() {
useEffect(() => {
console.log('Effect');
return () => console.log('Cleanup');
}, []);
return <div>Hello</div>;
}
// В React Strict Mode (development):
// Вывод:
// Effect
// Cleanup
// Effect
// Это нормально! React проверяет, что cleanup работает корректно
// В production будет только один Effect и один Cleanup
Как избежать ошибок
1. ESLint plugin for React Hooks
npm install --save-dev eslint-plugin-react-hooks
// .eslintrc.json
{
"extends": ["plugin:react-hooks/recommended"]
}
Плагин предупредит:
WARNING: Missing dependency 'userId' in useEffect hook
2. Правило: если используешь переменную в useEffect — добавь в зависимости
// ПЛОХО
function Component({ userId }) {
useEffect(() => {
console.log(userId); // используем userId
}, []); // но не добавили в зависимости!
}
// ХОРОШО
function Component({ userId }) {
useEffect(() => {
console.log(userId);
}, [userId]); // добавили в зависимости
}
Резюме
useEffect БЕЗ массива зависимостей:
- Запускается ПОСЛЕ КАЖДОГО рендера
- В 99% случаев это ошибка и приводит к бесконечным циклам
- Используется только в редких случаях (отладка, аналитика)
Правильное использование:
[](пустой массив) — запуск один раз при монтировании[dependency]— запуск, когда dependency меняется- Всегда добавляй используемые переменные в массив зависимостей
Инструменты:
eslint-plugin-react-hooks— поможет избежать ошибок- React DevTools Profiler — видеть, когда запускаются эффекты