点击打开按钮(事件侦听器)后,React 弹出框(模态)会自动关闭

问题描述 投票:0回答:1

目标: 我想在 React 中实现一个弹出框(模态)。 当用户单击按钮时,弹出窗口将打开。 当用户在弹出窗口外部单击时关闭弹出窗口。

逻辑: 使用状态有条件地渲染弹出框组件。 在popover组件中,添加事件监听器,监听文档的点击事件。 如果用户单击文档,它会将状态更改为 false 以不渲染弹出窗口组件。

问题: 如果我单击按钮打开弹出窗口,则会触发事件侦听器。 这样弹出窗口就会自动关闭。

我想知道为什么会发生这种情况。

import { useState } from "react";
import Popover from "./Popover";

const TaskButton = () => {
  const [isPopoverShown, setIsPopoverShown] = useState(false);

  const popoverOpenHandler = () => {
    setIsPopoverShown(true);
  };

  const popoverCloseHandler = () => {
    setIsPopoverShown(false);
  };

  return (
    <div>
      <button
        onClick={popoverOpenHandler}
      >
        button
      </button>
      {isPopoverShown && (
        <Popover isOpen={isPopoverShown} onClose={popoverCloseHandler}>
          hello
        </Popover>
      )}
    </div>
  );
};

export default TaskButton;

import React, { useEffect, useRef } from "react";

const Popover =({ onClose, children }) => {
  const popoverRef = useRef(null);

  useEffect(() => {
    
    const pageClickEvent = (event) => { 
      if (popoverRef.current !== event.target) { 
        onClose();
      }
    };

    document.addEventListener("click", pageClickEvent); 
    
    return () => {
      document.removeEventListener("click", pageClickEvent);
    };
  }, [onClose]);

  return <div ref={popoverRef}>{children}</div>;
}

export default Popover;

我的想法:

我认为问题出在事件冒泡和捕获上。

document.addEventListener("mousedown", pageClickEvent);
document.addEventListener("click", pageClickEvent, true);

因为当我更改其中之一的代码时,它会按照我的预期工作。

但我想知道为什么如果我将事件“click”更改为“mousedown”(或向上)它会起作用。 或者如果我将捕获选项更改为 true。

我认为只有当组件安装在 DOM 上时才会激活事件监听器。 因此,不应通过单击按钮打开组件本身来触发事件监听器。

javascript reactjs event-listener event-bubbling react-modal
1个回答
0
投票

由于事件传播,您正在观察此行为。

当您单击按钮打开弹出窗口时,单击事件首先由按钮本身捕获,然后向上冒泡到文档级别。由于您的事件侦听器位于文档上并且正在侦听任何单击事件,因此它会在按钮的单击事件后立即触发。

为了防止这种行为,您需要停止将按钮的单击事件传播到文档级别。您可以使用 e.stopPropagation() 方法来实现此目的。以下是修改 popoverOpenHandler 的方法:

const popoverOpenHandler = (e) => {
  e.stopPropagation();
  setIsPopoverShown(true);
};

通过在

popoverOpenHandler
内调用 e.stopPropagation(),可以防止单击事件传播到按钮本身之外。这意味着按钮单击不会触发文档的单击事件侦听器,并且当您尝试打开它时,您的弹出窗口不会立即关闭。

一些可能有用的其他资源:https://developer.mozilla.org/en-US/docs/Web/API/Event/stopPropagation

我希望这有帮助。

© www.soinside.com 2019 - 2024. All rights reserved.