useEffect — это швейцарский нож для работы со всеми внешними операциями в React-компонентах. Хук, который выносит за скобки JSX всё, что связано с внешним миром: данные, подписки, таймеры и DOM.
| Массив зависимостей | Поведение | Аналог в классах |
|---|---|---|
[] | Один раз после монтирования | componentDidMount |
[dep] | При изменении зависимости | componentDidUpdate |
| Нет массива | После каждого рендера | ❌ Опасный паттерн |
| Cleanup функция | Уборка перед повторным вызовом/размонтированием | componentWillUnmount |
Когда он реально нужен:
Что заменяет из классовых компонентов:
Хук useEffect — это один из самых важных хуков в React, который позволяет выполнять побочные эффекты в функциональных компонентах. Он объединяет в себе функциональность нескольких методов жизненного цикла из классовых компонентов.
useEffect — это хук, который принимает функцию, содержащую императивный код, который может изменять состояние приложения или взаимодействовать с внешними API. Эта функция выполняется после каждого рендера компонента (по умолчанию).
// Базовый синтаксис useEffect
import { useEffect } from 'react';
function MyComponent() {
useEffect(() => {
// Побочный эффект
console.log('Компонент отрендерен');
// Функция очистки (опционально)
return () => {
console.log('Компонент будет размонтирован');
};
}, []); // Массив зависимостей
return <div>Мой компонент</div>;
}Эффект без массива зависимостей (когда второй параметр опущен) выполняется после каждого рендера компонента:
import { useEffect, useState } from 'react';
function Component() {
const [count, setCount] = useState(0);
// Этот эффект выполнится после каждого рендера
useEffect(() => {
console.log('Эффект выполнен');
document.title = `Счетчик: ${count}`;
});
// Нет массива зависимостей!
return (
<div>
<p>Счетчик: {count}</p>
<button onClick={() => setCount(count + 1)}>
Увеличить
</button>
</div>
);
}// Отслеживание изменений заголовка страницы
function PageTitleUpdater({ title }) {
useEffect(() => {
// Обновляем заголовок при каждом рендере
document.title = title;
});
return <div>Страница: {title}</div>;
}
// Логирование всех изменений состояния
function Logger({ data }) {
useEffect(() => {
// Логируем каждое изменение данных
console.log('Данные изменены:', data);
});
return <div>Логгер: {JSON.stringify(data)}</div>;
}Массив зависимостей позволяет контролировать, когда именно должен выполняться эффект. Он сравнивает значения зависимостей между рендерами и выполняет эффект только при их изменении.
[] — эффект выполняется один раз после первого рендера[dep1, dep2] — эффект выполняется при изменении любой зависимостиimport { useEffect, useState } from 'react';
function Component() {
const [count, setCount] = useState(0);
const [name, setName] = useState('');
// Выполняется один раз (после первого рендера)
useEffect(() => {
console.log('Компонент смонтирован');
fetchData();
}, []); // Пустой массив зависимостей
// Выполняется при изменении count
useEffect(() => {
console.log('Счетчик изменился:', count);
}, [count]); // Массив с одной зависимостью
// Выполняется при изменении count или name
useEffect(() => {
console.log('Счетчик или имя изменились');
}, [count, name]); // Массив с двумя зависимостями
return (
<div>
<p>Счетчик: {count}</p>
<button onClick={() => setCount(count + 1)}>
Увеличить счетчик
</button>
<input
value={name}
onChange={(e) => setName(e.target.value)}
placeholder="Введите имя"
/>
</div>
);
}Пустой массив зависимостей [] означает, что эффект не зависит ни от каких переменных и выполнится только один раз:
import { useEffect } from 'react';
function Component() {
// Выполняется один раз после монтирования
useEffect(() => {
console.log('Этот код выполнится только один раз');
// Подписка на событие
const handleResize = () => {
console.log('Размер окна изменился');
};
window.addEventListener('resize', handleResize);
// Функция очистки
return () => {
window.removeEventListener('resize', handleResize);
console.log('Подписка отменена');
};
}, []); // Пустой массив зависимостей
return <div>Компонент</div>;
}Массив с зависимостями позволяет выполнять эффект только при изменении определенных значений:
import { useEffect, useState } from 'react';
function UserProfile({ userId }) {
const [user, setUser] = useState(null);
// Выполняется при изменении userId
useEffect(() => {
async function fetchUser() {
const response = await fetch(`/api/users/${userId}`);
const userData = await response.json();
setUser(userData);
}
if (userId) {
fetchUser();
}
}, [userId]); // Зависимость от userId
if (!user) return <div>Загрузка...</div>;
return (
<div>
<h1>{user.name}</h1>
<p>{user.email}</p>
</div>
);
}import { useEffect, useState } from 'react';
function DataFetcher() {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
// Загрузка данных один раз при монтировании
useEffect(() => {
async function fetchData() {
try {
const response = await fetch('/api/data');
const result = await response.json();
setData(result);
} catch (error) {
console.error('Ошибка загрузки:', error);
} finally {
setLoading(false);
}
}
fetchData();
}, []); // Пустой массив - выполнить один раз
if (loading) return <div>Загрузка...</div>;
if (!data) return <div>Нет данных</div>;
return (
<ul>
{data.map(item => (
<li key={item.id}>{item.name}</li>
))}
</ul>
);
}import { useEffect, useState } from 'react';
function WindowSize() {
const [size, setSize] = useState({
width: window.innerWidth,
height: window.innerHeight
});
// Подписка на изменение размера окна
useEffect(() => {
function handleResize() {
setSize({
width: window.innerWidth,
height: window.innerHeight
});
}
window.addEventListener('resize', handleResize);
// Очистка подписки при размонтировании
return () => {
window.removeEventListener('resize', handleResize);
};
}, []); // Выполнить один раз
return (
<div>
<p>Ширина: {size.width}px</p>
<p>Высота: {size.height}px</p>
</div>
);
}import { useEffect, useState } from 'react';
function Timer() {
const [seconds, setSeconds] = useState(0);
// Запуск таймера
useEffect(() => {
const interval = setInterval(() => {
setSeconds(prev => prev + 1);
}, 1000);
// Очистка интервала
return () => {
clearInterval(interval);
};
}, []); // Выполнить один раз
return (
<div>
<p>Прошло секунд: {seconds}</p>
</div>
);
}useEffect — это мощный инструмент для работы с побочными эффектами в React:
✅ Когда использовать:
Ключевые моменты:
[] означает однократное выполнение[dep1, dep2] выполняет эффект при их измененииПонимание работы useEffect позволяет эффективно управлять побочными эффектами и жизненным циклом компонентов в React-приложениях.
Хотите больше статей для подготовки к собеседованиям? Подписывайтесь на EasyAdvice добавляйте сайт в закладки и совершенствуйтесь каждый день 💪