Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Разница между useEffect и useCallback
Это два разных хука React с разными целями. Часто их путают, но они решают разные проблемы.
useEffect
Назначение: запуск побочных эффектов при изменении зависимостей.
Побочные эффекты — это операции, которые взаимодействуют с внешним миром:
- API запросы
- Подписки на события
- Работа с DOM
- Таймеры
import { useState, useEffect } from "react";
export function UserProfile({ userId }) {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
// Запускается когда userId изменится
useEffect(() => {
setLoading(true);
fetch(`/api/users/${userId}`)
.then(res => res.json())
.then(data => {
setUser(data);
setLoading(false);
});
}, [userId]); // Массив зависимостей
return <div>{loading ? "Загрузка..." : user.name}</div>;
}
Синтаксис:
useEffect(() => {
// Код побочного эффекта
return () => {
// Очистка (cleanup) — опционально
};
}, [dependencies]); // Зависимости
useCallback
Назначение: мемоизировать функцию, чтобы она не пересоздавалась на каждый рендер.
Это нужно для оптимизации производительности, когда функция передаётся в дочерние компоненты.
import { useCallback, useState } from "react";
export function List() {
const [items, setItems] = useState([]);
// Функция пересоздаётся только когда items изменится
const addItem = useCallback((newItem) => {
setItems([...items, newItem]);
}, [items]); // Зависимости
return <ListChild onAddItem={addItem} />;
}
Синтаксис:
const memoizedCallback = useCallback(() => {
// Код функции
}, [dependencies]);
Прямое сравнение
| Аспект | useEffect | useCallback |
|---|---|---|
| Цель | Запуск побочных эффектов | Мемоизация функции |
| Возвращает | undefined | функцию |
| Запускается | После рендера | На каждый рендер, но возвращает мемоизированную функцию |
| Cleanup | Поддерживает | Нет |
| Использование | API, подписки, DOM | Передача функции в props |
Практические примеры
Пример 1: Разница в поведении
import { useState, useEffect, useCallback } from "react";
export function Example() {
const [count, setCount] = useState(0);
// useEffect запускается ПОСЛЕ рендера
useEffect(() => {
console.log("Компонент отрендерился, count=", count);
}, [count]);
// useCallback мемоизирует функцию
const handleClick = useCallback(() => {
console.log("Клик, count=", count);
}, [count]);
return (
<>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
<button onClick={handleClick}>Log Count</button>
</>
);
}
Пример 2: Когда нужен useCallback
import { useCallback } from "react";
import { ChildComponent } from "./ChildComponent";
export function Parent() {
// БЕЗ useCallback — функция пересоздаётся на каждый рендер
// это заставит Child перерендериться даже если props не изменились
const handleSubmit = useCallback((data) => {
console.log("Form submitted:", data);
}, []);
return <ChildComponent onSubmit={handleSubmit} />;
}
Пример 3: Очистка в useEffect
import { useEffect, useState } from "react";
export function Timer() {
const [seconds, setSeconds] = useState(0);
useEffect(() => {
// Код эффекта
const interval = setInterval(() => {
setSeconds(s => s + 1);
}, 1000);
// Cleanup функция — очищает интервал
return () => clearInterval(interval);
}, []); // Пустой массив = эффект только один раз
return <div>Seconds: {seconds}</div>;
}
Правила использования
useEffect:
- Используй для всех побочных эффектов
- Правильно указывай зависимости
- Помни про cleanup функцию для отписок/очистки
- Не создавай бесконечные циклы
useCallback:
- Используй когда передаёшь функцию в React.memo компонент
- Используй для оптимизации в больших списках
- Не переусложняй — сначала напиши без мемоизации
- Помни про зависимости
Заключение
- useEffect = "делай что-то когда данные изменяются"
- useCallback = "помни мою функцию, чтобы не пересоздавать её"
Они часто используются вместе: useCallback для функции, которая передаётся, и useEffect для выполнения побочных эффектов при её изменении.