Выпадающая кнопка с React (за переключателем)

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

В этой статье я покажу, как я разрабатываю такой компонент в React… все начинается с определения «атомов» компонента, атомы сами являются компонентами.

Кнопка

Раскрывающаяся карточка

Родительский компонент (чтобы обернуть оба)

Давайте воспользуемся попутным ветром для ускорения стилизации, если вы еще не слышали о попутном ветре, пожалуйста, взгляните на сайт проекта… и поблагодарите меня позже. Хорошо, покажи мне код.

Кнопка атома

Раскрывающаяся карточка атома

Этот компонент ожидает простой массив строк для визуализации списка (простой неупорядоченный список), теперь мы передадим образец массива из родительского компонента. Конечно, мы можем еще немного разделить код и создать также компонент для элементов LI, но я решил, что нет.

Родительский компонент

Хорошо, у нас есть то, что нам нужно, давайте скроем карточку, добавив начальное состояние в false в нашем родительском компоненте и заключив компонент «DropDownCard» во встроенное условие.

Теперь наш список скрыт, и мы собираемся использовать метод «setOpen» для изменения значения «open» при каждом щелчке по нашей кнопке, используя его свойство «onClick».

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

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

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

О, ваниль, ваниль !!

Для ванильного подхода давайте добавим идентификатор к нашему родительскому компоненту div, а затем в функции handleClick проверим, не находится ли элемент, на который кликнул, не ближе всего к идентификатору, например:

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

Это круто, но зачем использовать ваниль в React? Кроме того, нам нужно явно знать значение идентификатора, чтобы использовать его внутри функции handleClick. Что, если нам нужно больше одного компонента раскрывающейся кнопки в одном пользовательском интерфейсе одновременно? Затем мы должны использовать один и тот же идентификатор для каждого из них или, что еще хуже, заставить их использовать разные идентификаторы и динамически передавать идентификатор функции handleClick для каждого случая, другими словами, простое раскрывающееся меню становится кошмаром и нет, удачно для нас у нас более динамичный подход с использованием полностью базового решения React.

Рефакторинг React.

Давайте воспользуемся перехватчиком UseRef React, чтобы решить эту проблему раз и навсегда, инициализируем константу как React.useRef (null),

Бывший. const drop = React.useRef (ноль)

затем удалите идентификатор из нашего родительского компонента и добавьте класс «раскрывающийся список» или «Дори», если вам нравится «В поисках Немо», тогда давайте изменим оценку сейчас с

! e.target.closest («# drop-down-wrapper») && open

to

! e.target.closest (`. $ {drop.current.className}`) && open

Поскольку ближайшему всегда нужен селектор, а не сам элемент, нам нужно передать селектор из нашего родительского компонента, мы делаем это, обращаясь к «className» из «current» из нашего ссылочного элемента и не забывая помещать «.» в от него, указывая, что это селектор.

Теперь наше окончательное решение выглядит так:

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