Как написать собственный хук, который будет гарантировать, что липкие всплывающие окна не испортят UX в вашем приложении React.

Прежде всего, сценарий, который нас беспокоит:

Допустим, в вашем приложении есть всплывающее окно, которое открывается, когда вы нажимаете на пользователя. В этом всплывающем окне вы отображаете основную информацию об этом пользователе. Помимо этого всплывающего окна предварительного просмотра профиля, у вас могут быть раскрывающиеся меню, из которых пользователь может редактировать или удалять некоторые элементы. Возможности безграничны, мы используем всплывающие окна для многих случаев использования в наших приложениях.

Однако что происходит, когда пользователь щелкает мышью или начинает прокрутку при открытом всплывающем окне? Мы хотим, чтобы это всплывающее окно исчезло - в противном случае у них будет всплывающее окно-призрак, которое просто не исчезнет из области просмотра приложения (если они специально не нажмут кнопку X этого всплывающего окна. Вы добавили кнопку X, справа ?).

Решение состоит из 3 шагов.

  1. Мы хотим идентифицировать элемент, в котором происходит прокрутка (проще говоря, идентификатор элемента, полоса прокрутки которого перемещается, когда вы прокручиваете эту страницу в своем приложении).
  2. Мы хотим добавить слушателя к этому элементу, который, в свою очередь, будет вызывать определенную нами функцию - в этой функции мы, конечно же, будем скрывать все, что нужно скрыть.
  3. Мы также хотим добавить слушателя для действия щелчка - если пользователь щелкает за пределами всплывающего окна, оно должно закрыться.

Установка действия для события прокрутки родительского элемента

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

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

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

Теперь предположим, что корневой компонент - в нашем случае прокручиваемый контейнер - который находится в корне нашего дерева компонентов, выглядит примерно так:

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

Использование крючка во всплывающем окне

В компоненте Popup мы будем использовать ловушку с тем, что ему нужно:

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

Следуя той же логике, вы можете вернуться к ловушке useOnScrollEffect, и вы заметите, что переменная fun также передается в массив зависимостей - это связано с изменением обратного вызова handleScroll, так что он определяет правильное значение свойства isPopupOpen.

Зачем нам нужно было передавать эти массивы зависимостей? С чисто точки зрения «это работает, оставь это», все было бы нормально без массивов зависимостей. Однако вы заметите, что без if (props.isPopupOpen) проверки вызов closePopup был бы бесполезен сотни раз. Вы можете проверить это, передав console.log(“onscroll") в теле handleScroll обратного вызова. Я прокручивал вниз 2 или 3 раза, и бревно было запущено более 400 раз. Только представьте, как мы сотни раз без толку устанавливали истинное значение на истинное.

Щелчок за пределами всплывающего окна

Для обработки события click away мы будем использовать компонент из MaterialUI: ClickAwayListener.

Мы изменим наше всплывающее окно так, чтобы его содержимое было заключено в этот компонент.

В результате, когда любой щелчок обнаруживается за пределами нашего всплывающего окна, он будет работать нормально и закроется сам. Мы также можем настроить ClickAwayListener таким образом, чтобы он распознавал другие события, кроме простого щелчка за пределами всплывающего окна. В компоненте есть свойство mouseEffect, которое принимает следующие значения, в зависимости от того, что вам нужно:

‘onClick’
‘onMouseDown’
‘onMouseUp’

Однако для текущей цели достаточно поведения по умолчанию. Вы заметите, что всплывающее окно закрывается в тот момент, когда вы начинаете прокручивать страницу или когда вы щелкаете за ее пределами.

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

Большое спасибо за чтение!

Больше контента на plainenglish.io