Реагируйте: stopPropagation () не работает? - PullRequest
1 голос
/ 30 марта 2020

У меня есть компонент нижнего колонтитула с функцией переключения модального компонента. В модальном компоненте у меня есть обертка для фона и модал, вложенный в эту обертку. Я установил функцию toggleModal в качестве опоры и добавил ее в обертку модальной. Я не хочу, чтобы самому модалу была назначена эта функция щелчка, поэтому я использовал stopPropagation() в своей функции, чтобы остановить всплывающее окно события, хотя это, похоже, не работает.

Компонент нижнего колонтитула:

const Footer = () => {
  const [showModal, setShowModal] = useState(false);

  function toggleModal(e) {
    e.stopPropagation();
    setShowModal(!showModal);
  }
  return (
    <div>
      <button onClick={toggleModal}>Modal toggle</button>
      <Modal show={showModal} toggle={toggleModal}>This is a modal</Modal>
    </div>
  )
}

Модальный компонент:

const Modal = () => {
  return (
   <div className="modal__wrapper" onClick={props.toggle}>
     <div className="modal p-3">
       <div className="modal__close" onClick={props.toggle} role="button" aria-hidden="true">
         X
       </div>
       {props.children}
     </div>
   </div>
  )
}

Ответы [ 2 ]

1 голос
/ 30 марта 2020

Вот что происходит:

  1. .modal или другой элемент внутри него щелкается. Слушатель не подключен к элементу, поэтому событие продолжает пузыриться до предков.
  2. Событие достигает значения .modal__wrapper, в котором есть прослушиватель для события click. Слушатель не различает, какой элемент был прямой целью события: сам элемент или один из его потомков. props.toggle() срабатывает, даже если целью был другой элемент внутри оболочки. Слушатель останавливает распространение. Событие перестает пузыриться, но в любом случае никто не слушает его выше в дереве.

Я бы посоветовал вам присоединить ссылку к оболочке и проверить, была ли цель события самой оболочкой.

Модальный компонент будет выглядеть так:

const Modal = (props) => {
  const wrapperRef = useRef();

  const handleClick = e => {
    if(e.target === wrapperRef.current) {
      props.toggle(e);
    }
  };

  return (
   <div className="modal__wrapper" onClick={handleClick} ref={wrapperRef}>
     <div className="modal p-3">
       <div className="modal__close" onClick={props.toggle} role="button" aria-hidden="true">
         X
       </div>
       {props.children}
     </div>
   </div>
  );
};
1 голос
/ 30 марта 2020

чтобы остановить всплывающее окно события, хотя это, похоже, не работает.

Вы имели в виду, что всплывающее событие не работает или просто модал не работает вообще? Я обнаружил две проблемы с кодом, которые после исправления, кажется, делают модальную работу. Кроме того, вы можете хотеть поведение e.preventDefault(), но я не уверен из вашего вопроса.

Проблемы и исправления:

  1. Отсутствует реквизит в сигнатуре метода: const Modal = (props) => {
  2. Не используется show реквизит для отображения / скрытия модального div: props.show && <div className="modal__wrapper" onClick={props.toggle}>

stopPropagation & protectDefault

Для просмотра различия в поведении stopPropagation и preventDefault, попробуйте добавить это radio под кнопкой. Вам нужно будет обновлять sh страницу каждый раз, когда вам нужно сбросить radio для эксперимента.

<input type="radio" name="gender" value="male" onClick={toggleModal}/>

preventDefault останавливает установку radio , он предотвращает установку значения по умолчанию для радиокомпонента.

stopPropagation будет , а не остановит установку radio, потому что он только останавливает всплывающее событие до родительские элементы. Было бы полезно на text <input> предотвратить такие события, как клавиша Enter, от воздействия на родительский элемент <form> для отправки (если это было необходимо).

Надеюсь, это поможет решить вашу проблему.

...