Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Зачем нужны deps в useCallback?
useCallback — это хук для мемоизации функций. Массив зависимостей (deps) в useCallback критически важен: он определяет, когда функция должна быть пересоздана. Без правильно настроенных зависимостей useCallback просто не работает.
Как работает useCallback без deps
Без массива зависимостей каждый рендер компонента создаёт новую функцию:
function Counter() {
const [count, setCount] = useState(0);
// Без deps - функция пересоздаётся каждый раз
const increment = useCallback(() => {
setCount(count + 1);
}); // Плохо!
return <ChildComponent onIncrement={increment} />;
}
function ChildComponent({ onIncrement }) {
// onIncrement каждый раз новая функция
// Даже если компонент обёрнут в React.memo, эффект не будет
return <button onClick={onIncrement}>Increment</button>;
}
Это O(n) лишних рендеров детских компонентов.
Зачем нужен массив deps
Массив зависимостей говорит React-у: "Пересоздай функцию только если эти переменные изменились". Это оптимизирует производительность:
function Counter() {
const [count, setCount] = useState(0);
const [name, setName] = useState('Alice');
// Функция пересоздаётся только если count изменился
const increment = useCallback(() => {
setCount(count + 1);
}, [count]); // deps указан!
// Функция пересоздаётся только если name изменился
const changeName = useCallback((newName) => {
setName(newName);
}, []);
return (
<div>
<ChildComponent onIncrement={increment} onChangeName={changeName} />
<p>Name: {name}</p>
</div>
);
}
function ChildComponent({ onIncrement, onChangeName }) {
// Обёрнут в React.memo - не рендерится без причины
console.log('Child re-rendered');
return (
<>
<button onClick={onIncrement}>Increment</button>
<button onClick={() => onChangeName('Bob')}>Change Name</button>
</>
);
}
const ChildComponent = React.memo(ChildComponent);
Правило: включай все зависимости
Все переменные, используемые внутри функции, должны быть в массиве deps. Это правило Hooks (ESLint плагин warn о нарушениях):
function Example() {
const [count, setCount] = useState(0);
const [multiplier, setMultiplier] = useState(2);
// Неправильно: забыли multiplier в deps
const multiply = useCallback(() => {
return count * multiplier; // multiplier из замыкания!
}, [count]); // Опасно!
// Правильно: указаны все зависимости
const multiply = useCallback(() => {
return count * multiplier;
}, [count, multiplier]);
return <div>{multiply()}</div>;
}
Если забыть зависимость:
- Функция будет использовать старые значения переменных
- Это ведёт к race conditions и bugs
- ESLint с плагином eslint-plugin-react-hooks поймёт это
Когда использовать пустой массив deps []
Пустой массив deps [] означает: "Функция никогда не меняется":
function Parent() {
// Эта функция создаётся один раз при монтировании
const handleClick = useCallback(() => {
console.log('Clicked');
}, []); // Пустой массив - функция никогда не меняется
return <Child onClick={handleClick} />;
}
Это полезно, если функция не зависит от никаких переменных компонента.
Практический пример: запросы к API
function UsersList() {
const [userId, setUserId] = useState(null);
const [data, setData] = useState(null);
// Создаём функцию один раз - она не зависит от внешних переменных
const fetchUser = useCallback(async (id) => {
const response = await fetch(`/api/users/${id}`);
return response.json();
}, []); // []!
// Эффект зависит от userId и fetchUser
useEffect(() => {
if (userId) {
fetchUser(userId).then(setData);
}
}, [userId, fetchUser]);
return (
<div>
<input
type="number"
value={userId}
onChange={(e) => setUserId(Number(e.target.value))}
/>
{data && <div>{data.name}</div>}
</div>
);
}
Когда useCallback не нужен
- Функция простая и быстрая - создание новой функции дешевле мемоизации
- Функция не передаётся в Child komponenty - нет смысла в мемоизации
- Child komponenty не обёрнуты в React.memo - useCallback не поможет
// Без useCallback - нормально
function Form() {
const [email, setEmail] = useState('');
// Простая функция - useCallback излишний
const handleChange = (e) => {
setEmail(e.target.value);
};
return <input onChange={handleChange} />;
}
Резюме: Значение deps
- deps = явный сигнал React-у когда пересоздавать функцию
- Правильные deps = корректная работа приложения
- Забытые deps = баги с устаревшими значениями
- Пустой deps [] = функция стабильна на весь lifetime компонента
- Используй ESLint плагин для проверки deps
Вывод: Массив зависимостей в useCallback - не просто фичура, это основной механизм управления жизненным циклом функции. Правильное использование deps критично для производительности и корректности React-приложений.