У меня проблема с компонентом React.js Dialog, который содержит список элементов. Также есть оверлей в Dialog. Он закрывается автоматически, когда пользователь нажимает на него. Но сценарий другой. Диалог также включает в себя список элементов, некоторые внешние ссылки которых обернуты вокруг элемента <a>, а некоторые - с <div>.

Но метод закрытия диалога работает некорректно. Диалог автоматически закрывается, когда я щелкаю внутри любого элемента списка.

Пожалуйста, посмотрите это:

Modal Dialog

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

Я все еще не могу понять, как правильно решить эту проблему?

Ссылка CodeSandbox

App.js

import React, { useState } from 'react';
import Dialog from './Dialog';
import './App.css';

const App = () => {
  const [isOpen, setIsOpen] = useState(false);

  const onClickHandler = (isFalse) => {
    if (!isFalse) {
      setIsOpen(false);
    } else {
      setIsOpen(!isOpen);
    }
  };

  return (
    <div>
      <button type="button" onClick={onClickHandler}>
        Open Dialog
      </button>
      <Dialog isOpen={isOpen} onClick={onClickHandler} />
    </div>
  );
};

export default App;

Dialog.js

import React from 'react';

const Dialog = (props) => {
  const { isOpen, onClick } = props;
  const onCloseHandle = () => {
    onClick(false);
  };

  return (
    <div
      className={isOpen ? 'dialog-wrap open' : 'dialog-wrap'}
      onClick={onCloseHandle}
    >
      <div className="dialog">
        <ul className="dialog-list">
          <li>
            <a
              href="https://reactjs.org"
              target="_blank"
              rel="noopener noreferrer"
            >
              React.js
            </a>
          </li>

          <li>
            <a
              href="https://reactjs.org"
              target="_blank"
              rel="noopener noreferrer"
            >
              Another Link
            </a>
          </li>

          <li>
            <div>Should Not Close onClick</div>
          </li>

          <li>
            <div>Should Not Close onClick</div>
          </li>
        </ul>
      </div>
    </div>
  );
};

export default Dialog;

< Сильный > App.css

*,:before,:after {
  box-sizing: border-box;
}

.dialog-wrap.open {
  display: flex;
}

.dialog-wrap {
  display: none;
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 999;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  padding: 16px;
  background-color: rgba(0,0,0,0.66);
}

@media (min-width: 640px) {
  .dialog-wrap {
    padding: 48px 32px;
  }
}

@media (min-width: 1024px) {
  .dialog-wrap {
    padding-left: 40px;
    padding-right: 40px;
  }
}

.dialog {
  position: relative;
  margin: auto;
  background-color: #fff;
  border: 1px solid rgba(0, 0, 0, 0.1);
  box-shadow: 0 12px 16px rgba(0, 0, 0, 0.08);
  border-radius: 4px;
  width: 500px;
}

.dialog-list {
  margin-bottom: 0;
  padding-left: 0;
  color: #333;
  list-style: none;
}

.dialog-list > li {
  border-bottom: 1px solid #eee;
  padding: 24px;
}

.dialog-list > li > a {
  color: #333;
  display: block;
  text-decoration: none;
}

.dialog-list > li > div {
  cursor: pointer;
}
0
Ven Nilson 16 Фев 2021 в 14:20

2 ответа

Лучший ответ

В этой ситуации я бы создал элемент .dialog-background и дал бы ему onCloseHandle. Я также добавляю свои элементы a в опору onCloseHandle as onClick

Если вы не хотите менять свое дерево реакций, вы можете решить это из следующего события:

<div
  className={isOpen ? "dialog-wrap open" : "dialog-wrap"}
  onClick={(e) => {
    if (!e.target.closest('.dialog') || e.target.closest('a')) {
      onClick(false)
    }
  }}
/>
1
Pooya 16 Фев 2021 в 11:58

Я думаю, что ваше событие click распространяется вверх по элементам и запускает onCloseHandle на вашем .dialog-wrap.

Самым простым решением этой проблемы было бы использование Event.stopPropagation() на <div className="dialog">

Например.

<div className="dialog" onClick={ e => e.stopPropagation() }>

(Технически React использует "синтетические события", но они по-прежнему включают параметр stopPropagation пока он взаимодействует с внутри React)

1
DBS 16 Фев 2021 в 11:26
66223400