⚛️ Прокачиваем навыки React с помощью слушателей событий

В процессе программирования с использованием React иногда требуется более гибкий инструмент, чем стандартный обработчик событий. Слушатели событий могут быть решением, которое вы искали.

Перевод публикуется с сокращениями, автор оригинальной статьи Stefan Metodiev.

***
Фото Ника Фьюингса на Unsplash

Если вы участвовали в проектах на JavaScript в качестве фронтенд/бекенд разработчика, то вы должны быть хорошо знакомы с прикреплением событий к документу, элементу или объекту окна через встроенный модуль событий.

React создает уровень абстракции над основным модулем JavaScript, чтобы предоставить оболочку событий (Synthetic Event wrapper), с помощью которой можно получить доступ к элементам Virtual DOM и манипулировать ими. В большинстве случаев это все, что нужно для передачи функции одному из Synthetic Event обработчиков.

Статья поможет понять:

  • как правильно добавлять, очищать и отслеживать слушателей событий;
  • как строить стратегии производительности и оптимизации слушателей;
  • зачем необходимо создавать пользовательские event listener;
  • для чего использовать традиционные и “реактивные” реализации.

1. Как правильно добавлять, очищать и отслеживать слушателей

Прежде, чем погрузиться в код и реализацию, давайте проясним процесс добавления событий в React и JavaScript. Мы можем добавить слушателя в объекты окна, документы или элемент в коде.

В любом случае лучше прикреплять таких слушателей на этапе монтирования компонента во избежание любого неожиданного поведения.

Вот как это делается в функциональном компоненте:

React.useEffect(() > {

         document.addEventListener(‘click’, addIngredientHandler);

         return ():void > document.removeEventListener(‘click’,                                             addIngredientHandler)

}, [])

Очень важно очистить и удалить слушателя после того, как он перестанет быть нужен, а это произойдет, когда компонент размонтируется. Если мы оставим слушателей болтаться без очистки, могут возникнуть серьезные проблемы с производительностью приложения.

Еще один способ убедиться, что слушатели находятся в нужных местах или успешно удалены – проверять их и контролировать. Сделать это можно в Chrome Dev Tools:

Когда мы открываем инструменты разработчика и переходим к некоему элементу (в нашем случае – к документу) можно видеть, что EventListener прикреплен к DOM, ожидая выполнения.

Поскольку в статье используется codesandbox, можно заметить дополнительных слушателей в списке ниже. Так все выглядело бы во вкладке Event Listeners при наличии нескольких слушателей на объектах window, document и element:

Подключено несколько слушателей

Если внимательно посмотреть на последний скриншот, можно увидеть события “contextmenu” и “auxclick”, добавленные из codesandbox в глобальное пространство имен событий.

2. Стратегии производительности и оптимизации

Еще раз подчеркнем, что во избежание каких-либо проблем со слушателями событий нужно правильно добавлять (на этапе монтажа компонента) и очищать их.

Когда мы понимаем, как наблюдать за слушателями, следует убедиться, что они настроены на оптимальную производительность.

В методе addEventListener есть третий аргумент, позволяющий указывать дополнительные параметры, такие, как свойство once:

React.useEffect(() > {

    document.addEventListener(‘click’, addIngreientsHandler, {

       once: true

    });

}, [])

- once

Свойство указывает, что listener должен быть вызван не более одного раза после добавления. Если оно принимает логическое значение true, то listener будет автоматически удален при вызове. В документации говорится, что опция автоматически удаляется после запуска слушателя, поэтому не нужно беспокоиться о ее очистке.

Еще один очень удобный флаг – passive option. С его помощью можно значительно улучшить производительность listener и сократить время отклика элементов. Вот как это выглядит:

React.useEffect(() > {

       document.addEventListener(‘click’, addIngreientsHandler, {

           passive: true
       });
}, [])

- passive

Логическое значение true сообщает, что указанная слушателем функция никогда не вызовет функцию preventDefault(). Если пассивный слушатель вызывает функцию preventDefault(), агент пользователя создаст предупреждение в консоли. Дополнительные сведения для изучения ключей можно найти в разделе улучшение производительности.

В качестве эксперимента автор проверяет производительность слушателя с опцией и без. При обычном слушателе время выполнения составляет примерно 164мс, а с passive option, время выполнения упало до 116мс – на 30% эффективнее.

3. Создание кастомных listener

React предоставляет нам набор событий, но иногда может понадобиться более гибкое решение: обработать сложную анимацию, пользовательское скролл-событие, вызывающее изменения UI, или попытаться избежать перекрытия событий click в глобальном пространстве имен.

Мы всегда можем создать собственные события:

const createCustomEvent = (eventName: string, additionalData: {[key: string]: string }): CustomEvent | null > {

         if (window) {

           return new CustomEvent(eventName, {

             detail: {
                   additionalData
            }
           });
        }

return null;
};

Разберем, что здесь происходит.

  • Мы ожидаем, что в метод createCustomEvent будут переданы два параметра: имя события и любые дополнительные данные, находящиеся в параметре detail.
  • Внутри тела метода мы проверяем, существует ли объект window. Если нет, событие не может быть присоединено, и мы вернем null. В ином случае вернем конструктор CustomEvent, создающий пользовательское событие и передающий любые данные внутрь объекта detail.

Большая часть работы сделана, но нам нужен еще один метод, который отправит созданное событие:

export const toggleSideDrawerHandler = (additionalData: {[key: string]: string }): void > {
         const typeOfEvent = createCustomEvent(‘toggleDrawer’, additionalData);
         document.dispatchEvent(typeOfEvent);
};

Теперь рассмотрим эту часть кода:

  • Во-первых, скрипт ожидает получения параметра из toggleSideDrawerHandler, который позже будет передан с вызовом события.
  • Во-вторых, вызывается метод createCustomEvent, которому передаются дополнительные данные и имя события.
  • И последнее, созданное событие отправляется в toggleDrawer всякий раз, когда будет вызван этот метод.

Когда методы событий созданы, осталось использовать их в действии. Можно прикрепить метод toggleSideDrawerHandler к любому элементу, а он вызовет toggleDrawer. В песочнице находится весь код с рабочей реализацией рассмотренного примера.

4. Использование традиционных реализаций

Использование слушателей событий в React – не то, чем можно регулярно злоупотреблять. Лучше использовать предоставляемый React по умолчанию Synthetic Event.

Представим ситуацию, когда необходимо вызвать action на «другой стороне» приложения, а передача нашего метода невозможна или реализация глобального состояния была бы излишней. В этом случае использование Event Listener можно считать правильным выходом из ситуации.

Наслаждайтесь и счастливого взлома!

Источники

ЛУЧШИЕ СТАТЬИ ПО ТЕМЕ

eFusion
01 марта 2020

ТОП-15 книг по JavaScript: от новичка до профессионала

В этом посте мы собрали переведённые на русский язык книги по JavaScript – ...
admin
10 июня 2018

Лайфхак: в какой последовательности изучать JavaScript

Огромный инструментарий JS и тонны материалов по нему. С чего начать? Расск...