Недавно на моем проекте мы переехали с 18 версии React на 19. Теперь у нас самый свежий на текущий момент React v19.2. Я занимался этим перед Новым годом в период код-фриза, поэтому было изучить новинки и рассказать о тех что могли бы быть нам полезны коллегам в формате презентации. Об этом опыте я не преминул упомянуть в одном из последних технических интервью.
Интервьюер оказался подготовленным и сразу решил проверить — не вру ли я, и задал задачу, которая предполагала использование нового хука useEffectEvent. Не буду строить из себя гения: я не вспомнил этот хук и решил задачу старыми методами. Сегодня же хочу провести работу над ошибками и поговорить об этом новом, довольно классном и полезном хуке.
Задачу выдумаем свою, чтобы не «сливать» чужие наработки.
Постановка задачи
Представим, что у нас есть компонент для сбора каких-либо метрик. И на каждый клик мыши в документе он должен отправлять событие, в которое полезной нагрузкой добавляется объект с какой-то статистикой, которая приходит строкой. Метод sendAnalytics импортируется откуда-то извне. Импорты и рендер JSX опустим, для описания текущей темы это лишнее.
Решаем по старинке
До React v19.2 мы бы могли написать код для решения описанной проблемы как-то так.
const AnalyticsTracker => ({ data }) {
useEffect(() => {
const clickListener = () => sendAnalytics(eventName, { data })
document.addEventListener('click', clickListener);
return () => document.removeEventListener('click', clickListener);
}, [data]);
}
На каждое обновление входящих через пропсы данных мы обязаны отписываться от слушателя события и создавать новый. Метод рабочий, но забудь отписаться и получишь утечку памяти.
На сцену выходит useEffectEvent
Сначала напишу решение в новом стиле, а потом обсудим что получилось
const AnalyticsTracker => ({ data }) {
const sendEvent = useEffectEvent((eventName) => { sendAnalytics(eventName, { data });
useEffect(() => {
const clickListener = () => sendEvent('user_click', { data })
document.addEventListener('click', clickListener);
return () => document.removeEventListener('click', clickListener);
}, []);
}
Что мы сделали. Мы вынесли логику, завязанную на изменяемые данные, из реактивного эффекта в отдельную функцию, которую создали через useEffectEvent. При этом получилось разделение по сути — useEffectEvent занят отправкой аналитики, useEffect — подпиской на событие и отпиской от него.
Итоги
Подробнее, конечно же, читайте в официальной документации. У хука есть ограничения и особенности, которые стоит знать. Я же подытожу так.
useEffectEvent— это дополнение к useEffect и использоваться они должны вместе (а также сuseLayoutEffectи useInsertionEffect)useEffectEventпозволяет декомпозировать логику, описанную в эффектах, что упрощает их поддержку и дебаггингuseEffectEventснижает риск уйти в бесконечный рендер, допустить утечку памяти и перегреть устройство пользователя
Словом, useEffectEvent — молодец. И вы, если дочитали до конца, тоже.







