Вопрос или проблема
У меня есть теги ul и th li, отображаемые из данных API, и я хочу скрыть ul, когда щелкаю вне его. Я использую useEffect с ref.current.contains(event.target), чтобы сделать это с помощью window.addEventListener(“mousedown”, fn). Эта функция используется для установки состояния в false, чтобы закрыть или скрыть ul, но когда я щелкаю на любом элементе li, reactjs воспринимает это как щелчок вне ul, поэтому я не могу выполнить никакое действие с этим элементом li.
Как я могу это исправить? Я пытался использовать event.stopPropagation(), но это не сработало.
Ответ или решение
Чтобы закрыть выпадающее меню или изменить поведение элемента при клике вне его в ReactJS, важно правильно обработать события клика. Ваша задача заключается в том, чтобы скрыть список ul
, когда пользователь нажимает мимо него, но сохранить возможность кликать на его элементы li
. Вот как это можно реализовать, следуя принципам реакции на события и использованию рефов.
1. Создание компонента с рефами
Для начала создадим компонент, в который будем помещать наш список ul
. Мы будем использовать useRef
для ссылки на наш элемент списка, что позволит нам легко проверять, был ли клик внутри него.
import React, { useState, useRef, useEffect } from 'react';
const DropdownMenu = () => {
const [isOpen, setIsOpen] = useState(false);
const dropdownRef = useRef(null);
const toggleDropdown = () => {
setIsOpen(prev => !prev);
};
const handleClickOutside = (event) => {
if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
setIsOpen(false);
}
};
useEffect(() => {
window.addEventListener("mousedown", handleClickOutside);
return () => {
window.removeEventListener("mousedown", handleClickOutside);
};
}, []);
return (
<div>
<button onClick={toggleDropdown}>Toggle Menu</button>
{isOpen && (
<ul ref={dropdownRef}>
<li onClick={() => console.log('Item 1 clicked')}>Item 1</li>
<li onClick={() => console.log('Item 2 clicked')}>Item 2</li>
<li onClick={() => console.log('Item 3 clicked')}>Item 3</li>
</ul>
)}
</div>
);
};
export default DropdownMenu;
2. Пояснение реализации
-
Использование
useRef
: Мы создаем рефdropdownRef
, который позволяет нам ссылаться на элементul
. Это дает возможность нам определить, был ли клик внутри данного элемента. -
Обработчик кликов: Мы определяем функцию
handleClickOutside
, которая проверяет, был ли клик внеul
. Если клик был вне, мы устанавливаем состояниеisOpen
вfalse
, что скрывает меню. -
Чистка эффекта: В
useEffect
добавляется и удаляется обработчик событияmousedown
, что обеспечивает чистоту и безопасность работы с памятью. Это важно для предотвращения утечек памяти, когда компонент будет размонтирован.
3. Примечания по решению проблемы с stopPropagation()
Ваше первоначальное использование event.stopPropagation()
не решает проблему, поскольку этот метод предотвращает всплытие события, но не изменяет обработку клика вне элемента. Вы правильно сделали, что проверяете, содержит ли реф элемент, на котором был совершен клик. Это позволит сохранить взаимодействие с элементами списка li
, не прерывая их поведение.
Заключение
Данное решение обеспечит правильную работу выпадающего меню в вашем React-приложении. С помощью использования рефов и обработки событий вы сможете эффективно управлять кликами по элементам, сохраняя пользователю удобный интерфейс. Убедитесь, что вы тестируете поведение на различных устройствах и браузерах для достижения максимальной отзывчивости и надежности.